Gå til innhold

Dekorerte C++ funskjoner


Anbefalte innlegg

Problemet mitt består i at jeg skal skrive noen assembly funksjoner, og jeg har skrevet en C++ versjon av alle sammen, men istedet for å bruke dumpbin e.l. for å finne dekorerte navn på en funksjon, hadde det vært hendig med et verktøy som kunne dekorere en C++ funksjon, som jeg bare limte inn i .asm fila, noen som vet om noen? jeg søkte, men fant bare linker til UndName.exe, men den går jo feil vei....

 

En ting til: er det noen som vet om et api kall e.l. for å finne ut alle funksjoner en dll eksporterer? hadde vært kjekt hvis man vil lage et verktøy som automatisk lager en .h fil for en dll :)

Lenke til kommentar
Videoannonse
Annonse

Spørs om Microsoft eksponerer noe grensesnitt til kompilatoren sin for å dekorere funksjoner, da. En mulighet kunne være å skrive en slags front-end til kompilator + dumpbin?

 

Når det gjelder eksporterte kall googlet jeg litt og fant i alle fall en forklaring om formatet. Du ser ut til å like å gjøre ting selv, så hvorfor ikke skrive API'et :_)

Lenke til kommentar
Gjest Slettet+6132

Spørsmålet er vel egentlig:

Hvorfor vil du "mangle" navn på en gitt funksjon? Vil du styre/overstyre kompilator? (Som typisk "hekter på" en @nn på hvert "entry" i en .dll).

Når det gjelder det andre spørsmålet er det mer relevant...

I tidlegere? versjoner av Windows/NT fantes den en "viewer" som man kunne se alle "entry-points" i en .dll.

Det brukte jeg ofte for å skrive program (C/C++, MF Cobol) for å kalle funksjoner dynamisk i en dll... f.eks. Kernel32.dll..

SLikt er jo ikke pent da.., men "må man så må man".. :)

Endret av Slettet+6132
Lenke til kommentar
En ting til: er det noen som vet om et api kall e.l. for å finne ut alle funksjoner en dll eksporterer? hadde vært kjekt hvis man vil lage et verktøy som automatisk lager en .h fil for en dll :)

Enig i den, hadde vært kjekt å ha.

Er ikke så veldig vanskelig å skrive en basic greie en som bare løper gjennom alle .h filene i en mappe og lager deklarasjoner da, som den til slutt legger i en .h fil.

Lenke til kommentar

Den vanlige framgangsmåten er å definere funksjonene med extern "C". Du vil da slippe problemet med dekorerte navn i C++. Nesten alle DLL-filer i Windows blir laget på denne måten og eksporterer sjelden dekorerte C++ navn.

 

#ifdef __cplusplus
extern "C" {
#endif

/* dine funksjoner her */

#ifdef __cplusplus
} /* extern "C" */
#endif

Hvis du likevel av en eller annen grunn ønsker å hente ut symboler i en DLL-fil har en fyr som heter Matt Pietrek skrevet noen artikler om temaet. De tar for seg PE (Portable Executable) og viser et eksempel på en DUMPBIN lignende sak.

 

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

 

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

Endret av kjetil7
Lenke til kommentar

Takker for alle innlegg, det var veldig nyttig. hvis jeg skriver den .dlll->.h saken, så skal jeg si ifra :)

 

Grunnen til at jeg trenger dette, er fordi jeg tenkte jeg skulle skrive matrix og vertex funksjoner i ASM, for å frigjøre noen hertz til annet bruk, men jeg skal beholde de gamle som de er, slik at enginen skal la seg compile under andre compilere og OS.

Lenke til kommentar

Hmm, dette virker ikke så vanskelig, når en exe fil lastes, lages det en tabell over pekere til alle funksjoner, så alle 'CALL' instruskjoner byttes ut med JMP DWORD PTR (og offset til hver enkel funksjon som skal kalles)

 

Tabellen over dette står det at skal ligge i .edata seksjonen, men jeg kan ikke finne noen .edata i noen dll filer.....

 

Har også funnet ut at en kan lete fram hvor export table ligger, ved å bruke OptionalHeader.DataDirectory

 

Så hvis jeg skal lage et program som laget .lib og .h filer, må jeg først liste alle eksporterte funksjoner, deretter lage en del som skriver en .lib fil med alle .dll funksjoner eksportert, og en del som lager header fil... virker ganske enkelt :) men vi får se.

 

Det jeg har fått til hitill, er at jeg klarer å liste alle sections, men ikke noe særlig mer en det, jeg klarer ikke å lese importerte dll-er og funksjoner engang.......

 

Jeg har også funnet ut at du kan bruke ImageHlp til dette (<Imagehlp.h>, Imagehlp.lib)

 

int _tmain(int argc, _TCHAR* argv[])
{


register int x;

FILE *fp;

IMAGE_DOS_HEADER  dhdr;
IMAGE_NT_HEADERS  nhdr;
IMAGE_SECTION_HEADER    *sec_hdr;

if(!(fp = fopen(argv[0], "rb")))
 return 1;

//fread(&dhdr, sizeof(dhdr), 1, fp);
fread(&dhdr, sizeof(dhdr), 1, fp);

fseek(fp, dhdr.e_lfanew, SEEK_SET);

fread(&nhdr, sizeof(nhdr), 1, fp);


//fread(&fhdr, sizeof(fhdr), 1, fp);

cout << "Machine:";
switch(nhdr.FileHeader.Machine)
{
case IMAGE_FILE_MACHINE_I386:
 cout << "Intel 32-bit processor";
 break;
case IMAGE_FILE_MACHINE_ALPHA:
 cout << "Alpha processor";
 break;
case IMAGE_FILE_MACHINE_AMD64:
 cout << "AMD 64 Processor";
 break;
case IMAGE_FILE_MACHINE_IA64:
 cout << "Intel Itanium 64 bit processsor";
 break;
default:
 cout << "Unknown processor";
}
cout << "\nNumber of sections:" << nhdr.FileHeader.NumberOfSections << "\n";

sec_hdr = new IMAGE_SECTION_HEADER[nhdr.FileHeader.NumberOfSections];

fread(sec_hdr, sizeof(IMAGE_SECTION_HEADER), nhdr.FileHeader.NumberOfSections, fp);

for(x = 0; x < nhdr.FileHeader.NumberOfSections;x++)
{
 cout << "\t" << sec_hdr[x].Name << "\t\t " << sec_hdr[x].VirtualAddress;
 if(!strcmp((char*)&sec_hdr[x].Name, ".idata"))
 	cout << " (import table)";
 if(!strcmp((char*)&sec_hdr[x].Name, ".rdata"))
 	cout << " (export table)";

 cout << "\n";
}

cout << "Number of symbols:" << nhdr.FileHeader.NumberOfSymbols << "\n\n";

cout << "Imported functions:";

if(!nhdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
 cout << " None\n\n";
else
{
 unsigned long address;
 unsigned long size;

 cout << "\n";
 char *str;
 IMAGE_IMPORT_DESCRIPTOR imp;
 memset(&imp, 0, sizeof(imp));
 imp.TimeDateStamp = 0;
 size = nhdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
 address = nhdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
 fseek(fp, address, SEEK_SET);
 for(;;)
 {
 	fread(&imp, sizeof(IMAGE_IMPORT_DESCRIPTOR), 1, fp);
 	if(!imp.TimeDateStamp)
   break;
 	//str = read_string(sec_hdr[idata_section].Misc.PhysicalAddress + imp.Name, fp);
 	cout << str << "\n";
 	free(str);
 }

}


cout << "Number of exports:";
if(!nhdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
 cout << "None\n";
else
{
 IMAGE_EXPORT_DIRECTORY expdir;
 fseek(fp, nhdr.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, SEEK_SET);
 fread(&expdir, sizeof(expdir), 1, fp);
 cout << expdir.NumberOfFunctions << "\n";

 char **fn_names = new char*[expdir.NumberOfFunctions];

 fseek(fp, expdir.AddressOfFunctions, SEEK_SET);

 for(x= 0;x<expdir.NumberOfFunctions;x++)
 {
 	unsigned long str_ptr;
 	fn_names[x] = read_string(str_ptr, fp);
 	cout << "  " << fn_names[x];
 }

}



fclose(fp);

cin.get();

  
delete [] sec_hdr;

return 0;


}

Endret av GeirGrusom
Lenke til kommentar

Nå har jeg ikke studert PE, men vil du ikke få problem med å hente ut riktige parametre til funksjonene du ønsker å skrive til header-filen din? Eventuelle C++ typer og lignende er det vel heller tvilsomt at blir bevart...

 

Skjønner at det er interessant å studere PE og gå litt inn i dybden, men jeg tror du ender opp med å eksportere extern "C" funksjoner. Det er en veldig elegant løsning etter min mening. Og du kan jo fortsatt bruke C++ internt i funksjonene.

 

MS har noen kompilatortillegg som lar deg eksportere klasser og lignende. Men du blir da bundet til at alle komponenter bruker samme kompilator og standardbibliotek hvis du bruker elementer derfra. Dette er vel en av hovedårsakene til at COM så dagens lys...

Lenke til kommentar
Gjest Slettet+6132

Enhver funksjon som er "bundlet" i en såkalt "extension-DLL" har ett sett med funksjoner/entrypoints med tilhørende parametre..

Som Kjetil7 antyder her.. dukket COM opp bl.a. for å støtte runtime mulighet for å sjekke ut parametre..

Så gjentar jeg spørsmålet..:

Hvorfor ønsker man å vite navn på funksjoenr i en DLL?

Jo.. normalt for å kunne kallle disse fra et-eller-annet gr.snitt/progr.språk..

Dette er "teknisk" kode og kan løses uten å blande inn kompilatorer/verktøy annet enn det man bruker for å kalle en gitt funksjon dynamisk i en gitt .DLL.

Det man må ha er selvsagt header-file/dokumentajon på API'et..dvs. paramtre inn/ut til en gitt funksjon..

Så kaller man den enkelt og greit fra sitt program..

I C/C++ ved LoadLibrary() og GetProcAddress(), i f.ek.s MF Cobol ved å CALL'e 'myDLL.dll'.. I Java ved å bruke JNI..

Dette er "stygt", men noen ganger nødvendig av ulike årsaker.. særlig i miljø der ulike språk/compiler/RTS (Run-Time-SYstems) skal "mixes".

Når man av performance-hensyn ønsker å "speede" koden sin.. kan man jo likegodt kode maskinkode (ASM). Uleselig, men funksjonell kode.. og så "hardware-bound" som man kan komme.. :)

Lenke til kommentar

Jeg skriver alltid én C++ funksjon først, som jeg legger inn i en

#ifdef EXTERN_FUNCTION

 

som bare betyr at koden er blitt kompilert av et annet verktøry, MASM, og C++ koden skal ikke brukes.

 

SSE og SSE2 er veldig enkelt å sjekk om prosessoren støtter, det er gjort ved å kalle

 

mov eax, 1

cpuid

 

og det ligger da som flags i EDX registeret, og kan sjekkes da med (EDX & 0x2000000 (SSE))

 

og deretter kalle SSE kode, hvis det er støttet, elle binde den med en funksjonspeker.

 

deretter, sparer man masse CPU!

 

forresten, med PE formatet, har jeg kokt ihop et foreløpig litt uferdig program i C#, det er mer eller en hex editor for PE filer, en kan velge en header i en listbox, høyreklikke og velge "Jump to offset" så går hex editoren til det området i hex dumpen, man kan også velge felt i property viewer, og gjøre samme saken, alle objekter arver IFileEntry som inneholder hvor i filen strukturen ligger, og hvis noen feil har det interface, kan hex editoren hoppe dit, dere kan prøve dere frem hvis dere gidder.

 

hadde håpet på å legge inn disassembler, men tror det kan bli litt mye jobb...

har ikke helt fått fram exports enda, mye fordi jeg fortsatt har hangover... :hrm:

 

Enjoy!

 

takk for alle inspill! dere har vært til uvurdelig hjelp, jeg skal legge noe av dette jeg har laget inn i spill motoren, for å bedre "modul" støtte, slik at det skal bli letter å utvikle, ved at enginen stort sett finner ut av hvordan biblioteket er laget, uten noe store "export" klasse typer, den kikker etter en funksjon som heter "GetImplementedInterface" og lister alle klasser som har dem i dll fila, for deretter å lage en komplett liste med klasser som kan instansieres i prosjektet. :yes:

 

:edit

 

ville legge til at jeg begynner å få inn en disassembler nå ;)

alt ble litt enklere når jeg skjønte hva RVA (Relative Virtual Address) var, og hvordan en gjorde de om til filpekere.

PEdit.zip

Endret av GeirGrusom
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...