2015-06-08 11 views
8

unterscheiden Ich versuche, die Ausgabe eines nm oder readelf -s auf einer ausführbaren Datei zu verarbeiten. Ich habe jedoch Probleme, statische Funktionen in der Ausgabe voneinander zu unterscheiden. HierWie kann ich statische Funktionen mit nm-oder Realelf-Ausgabe in C

ist das, was ich arbeite mit:

test.c

static int foo() { 
    int x = 6; 
} 

main() {} 

other.c

static int foo() { 
    int x = 5; 
} 

ich kompilieren diese in etwa so:

gcc -o test test.c other.c 

Und dann einen nm-Befehl ausführen, um die Symbole alle zu bekommen:

nm test 

unter denen die folgenden zwei Symbole (für meine statischen Funktionen) erscheinen:

00000000004004ed t foo 
0000000000400500 t foo 

Gibt es eine Methode in der Lage sein, um zu unterscheiden, aus welcher Datei die spezifische Foo-Funktion stammt? Oder muss ich vor dem Kompilieren etwas Magie machen, um das zu erreichen?

Ich sollte hinzufügen, dass für meinen Anwendungsfall habe ich Zugriff auf die endgültige binäre und die Objektdateien, die von ihm verwendet, aber ich kann es nicht selbst erstellen, um sicherzustellen, dass es eine Symboltabelle hat.

Danke!

+1

soweit ich weiß Quelldatei Info wird in Debug-Informationen gespeichert. Vollständig entferntes Binärprogramm wird keine solche Information haben. Um Debug-Informationen zu lesen, klicken Sie auf 'readelf' --debug-dump. Ähnliches --debug-syms für 'nm' –

+0

Kompiliere mit' -g' und benutze 'nm -l' – 4566976

+0

Ich sollte das für meinen Anwendungsfall hinzufügen, ich habe Zugriff auf die endgültige Binärdatei und die von ihr verwendeten Objektdateien, aber Ich kann Debug-Informationen in der Binärdatei nicht erstellen oder sicherstellen. – Andrew

Antwort

9

Ihre Frage setzt voraus, dass, da eine ausführbare Datei, können Sie immer die Namen der static (local) Funktionen entdecken, die in sie zusammengestellt wurden, nm oder ein anderes Werkzeug. So werden Sie in der Lage zu sehen, wenn zwei oder weitere solche Namen sind die gleichen und die Frage, wie zu entdecken, , welche Quelldateien sie aus kompiliert wurden.

Diese Annahme ist jedoch falsch. Im Falle von gcc, wenn Dateien mit der Optimierung -O0 kompiliert werden, dann werden lokale Symbole im Objekt Datei Symboltabelle ausgegeben werden. -O0 ist die Standardeinstellung, so dass es gilt für den Fall Ihrer:

gcc -o test test.c other.c 

Aber wenn Dateien auf einem höheren Optimierungsstufe zusammengestellt - wie sie sicherlich für einen Release-Build werden - dann werden lokale Symbole aus dem weggelassene Objekt Dateien Symboltabelle. Der Linker sieht sie also nie. Sie können also nicht von der ausführbaren Datei mit nm oder irgendetwas anderem wiederherstellen.

Stellen Sie sich Ihren Beispieldateien mit:

gcc -O1 -o test test.c other.c 

dann nm test wieder, und Sie werden feststellen, dass der:

00000000004004ed t foo 
0000000000400500 t foo 

verschwunden, zusammen mit allen anderen statischen Funktionsnamen.

In diesem Fall, wenn, wie Sie sagen, Sie können nicht kontrollieren, wie die ausführbare Datei erstellt wird, dann können Sie nicht sicher, dass es sogar möglich ist, für Ihre Frage entstehen.

Wenn Sie konnte steuern, wie die ausführbare Datei, um sicherzustellen, gebaut wird, dass Dateien mit -O0 kompiliert sind, dann gibt es mehrere Möglichkeiten, wie Sie die statische Funktion Namen zu Quelldateien binden können.Zwei gleich Einfältigen wäre:

readelf -s test 

und

objdump -t test 

von denen jeder eine Quelldateinamen an der Spitze jedes Stück Symbole aufgelistet, die von ihm kommen.

(Und wenn es zu sagen braucht, die gdb Ansatz @Amol die Einschränkung nicht vorgeschlagen von nicht entziehen, dass die ausführbare Datei mit Optimierung -O0 kompiliert worden sein)

2

Möglicherweise müssen Sie die ELF-Symboltabelle lesen und den ELF32_ST_BIND-Wert extrahieren.

Nach der ELF-Spezifikation (siehe http://flint.cs.yale.edu/cs422/doc/ELF_Format.pdf) die Werte für ELF32_ST_BIND können sein:.

 Name   Value 
    STB_LOCAL  0 
    STB_GLOBAL  1 
    STB_WEAK  2 
    STB_LOPROC 13 
    STB_HIPROC 15 

Wo STB_LOCAL definiert ist „Lokale Symbole sind nicht sichtbar außerhalb der Objektdatei enthält, deren Definition sein Lokale Symbole Derselbe Name kann in mehreren Dateien vorhanden sein, ohne sich gegenseitig zu stören. " die mit statischen C-Funktionen recht gut zusammenpassen.

Zum Beispiel nehmen Sie probieren und etwas ändern:

test.c: 

    static int foo() { 
     int x = 5; 
    } 

    int bar() 
    { 
     int y = 6; 
    } 

    main() {} 

    other.c: 

    static int foo() 
    { 
     int x = 7; 
    } 

und Kompilieren mit gcc -o test test.c other.c und Blick auf die Symboltabelle (viele Einträge entfernt):

readelf -s test 
    Num: Value   Size Type Bind Vis  Ndx Name 
    37: 00000000004004f0 13 FUNC LOCAL DEFAULT 13 foo 
    39: 0000000000400510 13 FUNC LOCAL DEFAULT 13 foo 
    52: 00000000004004fd 13 FUNC GLOBAL DEFAULT 13 bar 

Wir können sehen, dass die zwei statischen Funktionen erscheinen als LOCAL und die eine "normale" Funktion zeigt ein GLOBAL

Hinweis: während diese Methode mit Nicht-Debug-Dateien funktioniert, wenn Th Die letzte Datei wird entfernt, wir können diese Methode nicht verwenden.

3

Ich habe folgende Sequenz ausprobiert.

Wenn Sie die Ausgabedatei ohne Debugging-Symbole entfernt haben, können Sie mit der Datei gdb eine Objektdatei erstellen. die Befehle folgen, wie unten:

$ gdb a.out 

geben als Ausgabe folgende

Reading symbols from /home/amol/amol/a.out...(no debugging symbols found)...done. 

Dann (gdb) wird Terminal

Give folgende Befehle nacheinander kommen in ((gdb) Prompt kommen standardmäßig als Sie weiter mit Eingabe von Befehlen)

(gdb) maint print symbols filename 
(gdb) maint print psymbols filename 
(gdb) maint print msymbols filename 

Jetzt in Ihrem Ordner können Sie eine Datei mit dem Namen Dateiname sehen. Öffnen Sie diese Datei in Texteditor können Sie Informationen sehen wie folgt:

[ 8] t 0x80483b4 foo section .text test.c 
[ 9] T 0x80483c3 main section .text other.c 
[10] t 0x80483c8 foo section .text other.c 

Hier können Sie deutlich, dass sehen, die foo() Funktion kommen aus dem .c Datei. Hoffe, das hilft dir.

+0

Vielen Dank für die Antwort. Ich hätte wahrscheinlich erwähnen sollen, dass meine Methode irgendeine beliebige ausführbare Datei aufnehmen soll, so dass eine Symboltabelle sogar weggelassen werden könnte und die Methode trotzdem funktionieren sollte. Wenn ich jedoch Ihre Antwort und einige andere sehe, glaube ich nicht, dass dies möglich ist. Danke noch einmal! – Andrew

0

Wenn es auf jedem gestrippt ausführbare Implantate könnte funktionieren sollte eine Zeichenfolge in die Funktionen und suchen Sie in der ausführbaren Datei.

#define STR1(x) #x 
#define STR(x) STR1(x) 
#define FUNCID(funcname) __asm__ __volatile__ (\ 
    "jmp 1f;"\ 
    ".string \"" __FILE__ "/" STR(funcname) "()\";"\ 
    "1:"\ 
) 

static int foo() { 
    FUNCID(foo); 
    return rand(); 
}