2016-04-01 3 views
6

Betrachten Sie die folgende Funktion:Wie erzwinge ich gcc, um eine Funktion direkt im PIC-Code aufzurufen?

extern void test1(void); 
extern void test2(void) { 
    test1(); 
} 

Dies ist der Code gcc ohne -fpic auf amd64 Linux erzeugt:

test2: 
    jmp test1 

Wenn ich mit -fpic kompilieren, gcc ausdrücklich die PLT-Anrufe über Symbol Zwischenschaltung zu aktivieren:

test2: 
    jmp [email protected] 

Dies ist jedoch nicht unbedingt erforderlich d für positionsunabhängigen Code und könnte weggelassen werden, wenn ich nicht unterstützen möchte. Bei Bedarf schreibt der Linker das Sprungziel auf das PLT-Symbol um.

Wie kann ich, ohne den Quellcode zu ändern und ohne den kompilierten Code für eine gemeinsam genutzte Bibliothek ungeeignet zu machen, Funktionsaufrufe direkt an ihre Ziele senden, anstatt explizit durch den PLT zu gehen?

+1

Meinst du für Anrufe innerhalb Ihrer Bibliothek/ausführbare Datei? Das sollte irgendwie möglich sein, vielleicht durch die Definition eines privaten Alias ​​oder etwas. Aber für Aufrufe von Funktionen in Bibliotheken, mit denen Sie nur dynamisch verknüpfen, bin ich nicht sicher, ob der Laufzeit-Linker * solche Referenzen auflösen kann. –

+0

@PeterCordes Ohne '-fpic' schreibt der Linker Referenzen auf Symbole automatisch an PLT-Referenzen, wo dies erforderlich ist. Das ist das Verhalten, das ich möchte, d. H. Der Compiler erzeugt normale Aufrufe an alle Funktionen, und der Linker schreibt die Aufrufe neu, die zu einem anderen gemeinsamen Objekt gehen. – fuz

+1

Führt ['-fno-semantic-interposition'] (http://stackoverflow.com/questions/35745543/new-option-in-gcc-5-3-fno-semantic-interposition) das aus, was Sie wollen? Siehe auch http://stackoverflow.com/questions/34102989/shared-object-in-linux-without-symbol-interposition-fno-semantic-interposition. Ist diese Frage ein Duplikat von beiden? –

Antwort

1

Wenn Sie erklären test1() versteckt (__attribute__((__visibility__("hidden"))), wird der Sprung direkt.

Jetzt test1() möglicherweise nicht in der Quelle-Übersetzungseinheit definiert wird als verstecktes, aber ich glaube, kein Schaden aus dieser Diskrepanz mit Ausnahme der C-Sprache kommen soll Stellen Sie sicher, dass &test1 == &test1 zur Laufzeit für Sie unterbrochen wird, wenn einer der Zeiger über einen verborgenen Verweis und einer über einen öffentlichen Verweis abgerufen wurde (der öffentliche Verweis wurde möglicherweise über Preloading oder ein DSO vor dem aktuellen im Lookup-Bereich eingefügt) , während die versteckte Referenz (die zu direkten Sprüngen führt) wirksam jede Art von Interposition verhindert)

Ein geeigneterer Weg, um damit umzugehen, wäre, zwei Namen für test1() -einen öffentlichen Namen und einen privaten/versteckten Namen zu definieren.

In gcc und clang kann dies mit etwas Alias-Magie geschehen, was nur in der Übersetzungseinheit möglich ist, die das Symbol definiert.

Makros können es schönere machen:

#define PRIVATE __attribute__((__visibility__("hidden"))) 
#define PUBLIC __attribute__((__visibility__("default"))) 
#define PRIVATE_ALIAS(Alias,OfWhat) \ 
    extern __typeof(OfWhat) Alias __attribute((__alias__(#OfWhat), \ 
           __visibility__("hidden"))) 

#if HERE 
PUBLIC void test1(void) { } 
PRIVATE_ALIAS(test1__,test1); 
#else 
PUBLIC void test1(void); 
PRIVATE void test1__(void); 
#endif 

void call_test1(void) { test1(); } 
void call_test1__(void) { test1__(); } 

void call_ext0(void) { void ext0(void); ext0(); } 
void call_ext1(void) { PRIVATE void ext1(void); ext1(); } 

Die oben compiliert (O3, x86-64) in:

call_test1: 
     jmp  [email protected] 
call_test1__: 
     jmp  test1__ 
call_ext0: 
     jmp  [email protected] 
call_ext1: 
     jmp  ext1 

(Definition 1 HIER = inlines zusätzlich den test1 Aufruf da es klein ist und lokal und -O3 ist eingeschaltet).

Live-Beispiel unter https://godbolt.org/g/eZvmp7.

-fno-semantic-interposition wird den Job auch tun, aber es bricht auch die C-Sprache Garantie, und es ist eine Art von einem großen Hammer, der nicht die Granularität von Aliasing hat.

+0

Ich denke '' fno-semantic-interposition' ist was ich wollte. – fuz

2

Wenn Sie nicht den Quellcode ändern, können Sie einen großen Hammer: -Bsymbolic Linker-Flag:

Wenn Sie eine gemeinsame Bibliothek erstellen, binden Verweise auf globale Symbole auf die Definition innerhalb der freigegebene Bibliothek, falls vorhanden. Normalerweise ist es möglich, dass für ein Programm, das mit einer gemeinsam genutzten Bibliothek verknüpft ist, die Definition in der gemeinsam genutzten Bibliothek überschreibt. Diese Option ist nur auf ELF-Plattformen sinnvoll, die gemeinsam genutzte Bibliotheken unterstützen.

Aber Vorsicht, dass es bricht, wenn einige Teile der Bibliothek auf Symbol Interposition angewiesen sind. Ich würde empfehlen, mit versteckten Funktionen zu arbeiten, die nicht exportiert werden müssen (indem man sie unsichtbar macht) oder sie durch versteckte Aliasnamen aufruft (speziell entwickelt, um PLT-losen Intra-Library-Aufrufe kontrolliert auszuführen).

Verwandte Themen