Grösse einer Funktion ermitteln (C++)

Vieleicht ist das ganz simpel, aber ich komme einfach nicht darauf...
Ich möchte die Grösse (Speichergrösse) einer funktion ermitteln, die sie einnimmt. Wie kann ich das verwirklichen? Ich habe momentan einfach gar keine Idee...

Vielen Dank schon einmal!
 
Also meine Idee wäre so:

Code:
void myFunc()
{
	__asm MOV EAX, 0xFFFFFFFF
	__asm RET
}
void myFuncEnd(){}

int main()
{
   unsigned long myFuncLen = (long)myFuncEnd - (long)myFunc;
   return myFuncLen;
}
 
Original von +++ATH0
Also meine Idee wäre so:

Code:
void myFunc()
{
	__asm MOV EAX, 0xFFFFFFFF
	__asm RET
}
void myFuncEnd(){}

int main()
{
   unsigned long myFuncLen = (long)myFuncEnd - (long)myFunc;
   return myFuncLen;
}

Naja, dabei nimmt man aber an, dass die Funktionen auch schön so in der Reihenfolge in der Binary landen, wie sie im Source stehen, was nicht unbedingt der Fall sein muss. Völlig sicher kann man das aber auch nicht festellen, da man es vom Sourcecode aus nicht wissen kann.
 
Original von Lesco
[...]
Naja, dabei nimmt man aber an, dass die Funktionen auch schön so in der Reihenfolge in der Binary landen, wie sie im Source stehen, was nicht unbedingt der Fall sein muss. Völlig sicher kann man das aber auch nicht festellen, da man es vom Sourcecode aus nicht wissen kann.

Stimmt. Basiert auf Annahmen, wie das Kompilat aussehen könnte. Muss man dann als Programmierer selbst nachprüfen.
Es gibt sonst auch leider keine andere sichere Methode um die Funktionslänge aller möglichen Funktionen festzustellen.

Selbst, wenn man mit einem Length-Disassembler sich bis zu einem Return durchhangelt, kann es sich immer noch zum Beispiel um eine Funktion mit mehreren returns handeln.
Manchmal ist das Funktionsende-Problem, fehlgeschlagene Stack-Analyse, sowie auch die Unterscheidung zwischen Code/Data eines Kompilats statisch nicht entscheidbar, also selbst IDA hat da an einigen speziellen Stellen keine Chance. Da muss Emulation her, und selbst dann sind alle möglichen Execution-Paths nicht abgedeckt.
Schwierige Sache.
 
Original von Lesco
Naja, dabei nimmt man aber an, dass die Funktionen auch schön so in der Reihenfolge in der Binary landen, wie sie im Source stehen, was nicht unbedingt der Fall sein muss. Völlig sicher kann man das aber auch nicht festellen, da man es vom Sourcecode aus nicht wissen kann.

ohne eingeschaltete Optimierungen würde das Ergebnis wohl noch am ehesten richtig sein.
Ansonsten denke ich, dass es keine allzu einfache Möglichkeit gibt, dies in C++ zu verwirklichen.
 
Jetz eher etwas pseudocode aber sollte so ca funktionieren:

Code:
void MyFunction()
{
  //Code here
}

int main()
{
  int Size = 0;
  BYTE* FunctionPtr = &MyFunction;

  while(*FunctionPtr != 0xC3)
  {
    Size++;
    FunctionPtr++;
  }

  cout << "Function Length: " << Size << endl;
}

Also was der Code tut ist einfach erklärt:
Er zählt solange 1 dazu bis er an eine Stelle angekommen wo ein 0xC3 steht (Opcode für RETN)
Solange du kein Inline-Assembler mit einem RETN verwendest sollte der Code großteils funktionieren.

Mfg Inliferty

Edit:
Wie ich seh ist mir +++ATH0 zuvorgekommen :P
 
Original von Inliferty
Also was der Code tut ist einfach erklärt:
Er zählt solange 1 dazu bis er an eine Stelle angekommen wo ein 0xC3 steht (Opcode für RETN)
Solange du kein Inline-Assembler mit einem RETN verwendest sollte der Code großteils funktionieren.

Dabei darfst du innerhalb der Funktion auch kein return verwenden(egal ob in inline asm oder nicht) und auch keine Zahlenwerte die 0xc3 beinhalten(egal ob man die nun dezimal oder nicht aufschreibt). Genauso weiß ich nicht, ob C3 nicht noch als Teil von anderen Opcodes auftauchen kann.
Ein weiteres Problem ist, dass viele Compiler eventuell retn 4 oder so verwenden, um noch Bytes vom Stack zu entfernen. Das würde dann etwa zu 0xcb 0x04 führen.
Ich glaube ++ATH0s Methode ist da doch sicherer.
 
Danke für die vielen Antworten. Besonders für das Beispiel von +++ATHO, obwohl leider irgdwie keines der Beispiele ganz zutrifft, wenn ich mit verschiedene Funktionsrössen mit der Grösse der Datei vergleiche, wenn ich nur die Funktion verändere ;)
 
Vlt. erklärst du uns was du genau machen möchtest?
Die Größe der Executable hängt von viel mehr ab als nur von dem Platz, welches alle Variablen und Funktionen einnehmen. (Beim PE-Format und ELF am Alignment und den Sektionen (Segmente))
 
Es handelt sich um ein Programm zum Test von Evaluationsfunktionen. Dabei werden automatisch Geschwindigkeit, (geplant) Grösse, benötigter Speicher zur Verarbeitung, Abdeckungsgrad und Verbesserungsmöglichkeiten ermittelt (erst ca. zu 1/3 verwirklicht, da ziemlich komplex).
Die Grösse ist gar nicht so wichtig, aber damit soll auch die Möglichkeit geboten werden, das verhältnis von entrollten und zusammengefassten Funktionen zu vergleichen.
 
Wenns so ist: man könnte "Marker" bauen (sowas wird bei Kopierschutzintegration gerne genutzt :) ). Also z.B am Anfang der Funktion über inline Asm oder andere Features einen
eindeutigen Hash sowie am Ende. Bleibt dann nur noch der Bytescan sowie das Problem mit der Wegoptimierung aller nicht erreichbaren Codeteile durch den Compiler (wenn man es nach return platziert). Also notfalls vor dem letzen return platzieren und dann mit ~1 Byte Ungenauigkeit leben:
Code:
_asm
{
  jmp weiter
  db 12,34,56,78,90,12,34 ... <- eindeutiger Hash
  weiter:
}

Btw: sollte loop unrolling eigentlich nicht vom Compiler vorgenommern werden?

PS: nun sehe ich meine Vorurteile wieder bestätigt - C++ ist keineswegs allmächtig, sondern nur richtig vermurkst :D
 
Zurück
Oben