2016-06-13 9 views
6

Jeder Maschinencode über Textabschnitt in der Objektdatei hat Adresse, es wird von 0 zu einer Zahl.statische Verlagerung über c

Wenn der Linker alle Objektdateien verknüpft, ändert sich die Adresse der Anweisung.

Ich kann nicht sehen, ob der Linker Anweisung über Textabschnitt nacheinander lesen wird, um jede Befehlsadresse zu ändern.

Disassembly of section .text: 

00000000 <_start>: 

    0: bf 00 00 00 00   mov $0x0,%edi 
    5: 8b 04 bd 00 00 00 00 mov 0x0(,%edi,4),%eax 
    c: 89 c3     mov %eax,%ebx 

durch verknüpft

08048074 <_start>: 

    8048074: bf 00 00 00 00   mov $0x0,%edi 
    8048079: 8b 04 bd a0 90 04 08 mov 0x80490a0(,%edi,4),%eax 
    8048080: 89 c3     mov %eax,%ebx 

genau wie 0 → 8.048.074 und so weiter.

+0

Nicht sicher, ob das das ist was du suchst, aber der Prozess ist in der '- beschrieben fpic' verwandter Abschnitt in ['man gcc'] (http://linux.die.net/man/1/gcc). – CristiFati

+8

Was ist die eigentliche Frage? – Art

+0

Es gibt keinen Maschinencode, bis der Linker ihn erstellt hat, also verstehe ich nicht, was Sie meinen. "Lesen Sie Anweisungen über Textabschnitte nacheinander" von wo? – Lundin

Antwort

2

Okay, ich nehme an, Sie verwenden ein Unix-basiertes System, da dies wie die Ausgabe des Befehls objdump aussieht, aber was ich weiß, ist dies sowohl für ELF- als auch PE-Dateien relevant.

Also beginnen wir, zuerst, wenn Sie c verwenden, kompilieren Sie einige Modelle in Objektdateien und verknüpfen Sie sie schließlich miteinander, wie früher gesehen. zB:

  • m1.c ->m1.o
  • m2.c ->m2.o
  • main.c + m2.o + m1.o ->main.exe

wir einige c Programme m1.c/m2.c, die einige Funktionen definiert genannt haben, die von main.c aufgerufen werden, werden schließlich alle miteinander verbunden und in main.exe wh zusammengefasst Ich bin voll ausführbar.

Jetzt tauchen wir ein und sehen, was unter der Haube passiert ist. Zuerst möchte ich mit einem sehr wichtigen Anfang beginnen, innerhalb der endgültigen ausführbaren Datei, in unserem Beispiel (main.exe) sind alle Adressen VOLLGESCHLOSSENE VIRTUELLE ADRESSEN (dies ist nicht unbedingt wahr wegen eines Konzepts namens PIE/PIC aber denn nun lassen Sie uns nicht in sie erhalten)

daher innerhalb Sie ausführbar sind, funktionieren foo innerhalb m1.o würde eine aufgelöste Adresse (zB 0x400100), innerhalb main.exe wenn foo genannt wird man so in der Demontage etwas sehen werden als

call 0x400100 

jetzt ist das, was konzeptionell passiert, jetzt lassen Sie uns in was passiert eigentlich. beim Holen von Anweisungen, zB jmp oder call Befehl eine Adresse wird als Operand gegeben und dann das Befehlsregister Ihres Prozessors wird auf die Adresse als Operand geändert, so ist Ihre Frage klug, sollte der Linker Anweisung für Anweisung gehen, finden Sie in der muss geändert werden und ändern Sie es? Naja, der Linker macht das einfach nicht, es ist viel schlauer.

Zunächst generiert der Compiler beim Kompilieren Sprünge und Aufrufe an innere Module (z. B. jmp an eine Adresse, die in unserem Beispiel bereits innerhalb von m1.o liegen sollte) relativ zur aktuellen Ausführung der Anweisung. was bedeutet das? Nehmen wir an, wir haben einige if-Anweisungen, die zu Sprüngen an einige Adressen kompiliert würden. Der Compiler ist schlau genug, um einen relativen Sprungoperanden zu verwenden und den Offset zwischen Befehlen zu setzen Es ist irrelevant, an welche Adresse der Code geladen wird, da die Aufrufe relativ zur aktuellen Anweisung sind und der Offset zwischen Befehlen einer Objektdatei durch die Verknüpfungsstufe statisch bleibt.

jetzt hier ist, wo die Dinge ein wenig komplexer werden, haben wir abgedeckt, wie die Linker wechselnden Adressen innerhalb m1.o vermeidet, was nun, wenn m2.o Anrufe definierte Funktionen in m1.o beide sind ausführbare Dateien, und es gibt keine Möglichkeit, auf der Erde, dass der Compiler kann den Offset zwischen ihnen annehmen, da sie beide keine Ahnung haben mit wie vielen anderen Modellen sie verbunden sind, wie ist das gelöst? Symbol- und Relocation-Tabellen werden eingeführt.

  • Symboltabelle - Eine Tabelle, die alle Symbole im Modell enthalten - ein Symbol ist etwas, das andere Modelle müssen nach dem Namen erkennen, wie Funktionen und globale Variablen.
  • Umlagerungstabelle - Eine Tabelle, die alle "Vorkommen" der Symbole in einigen Modellen enthält.

Sie haben vielleicht schon einmal davon gehört, aber jetzt werde ich Ihnen das erklären. vor dem Einstieg, muss ich warnen, dass ich mit ELF-Format-Dateien vertrauter bin, aber so viel wie ich weiß, ist das Konzept PE-Dateien auf die gleiche Weise funktionieren.

Look let in diesem Beispielcode

#include <stdio.h> 
/** file: m1.c **/ 

extern void goo(); 

void foo() 
{ 
    printf("I am foo()!\n"); 
    goo(); 
} 

und

#include <stdio.h> 
/** file: m2.c **/ 

void goo() 
{ 
    printf("I am goo()!\n"); 
} 

wenn m1.o innerhalb der Objektdatei kompilieren, würde es eine Tabelle sagen, so etwas wie dieses

SYMBOLE sein: foo - > bei Offset X innerhalb der Datei, goo -> UNDEFINIERT UMZUG: goo -> bei Offset Y innerhalb der Datei,

Nun, was das bedeutet ist, dass der Compiler eine Tabelle generiert, die alle Funktionen des Modells sammelt und bestimmt, ob sie definiert sind - es gibt den Offset, in dem die Funktion definiert ist archiviert, und wenn es nicht definiert ist, würde es

auch sagen, dass innerhalb dieses Modells goo bei Offset X aufgerufen wird und es muss verlagert werden (Wir werden zu meinem Punkt kommen, es ist die Antwort auf Ihre Frage!)

Bei der Verknüpfung in eine ausführbare Datei, der Linker nimmt alle Symbole aller Objektdateien, löst einige Adressen in ihnen, und geht dann durch jede Symboltabelle jeder Objektdatei, sieht und bestimmt, welche Symbole noch undefiniert sind, dann geht durch die Umlagerungstabelle und schaut, welche Aufrufe an Symbole gemacht werden, die undefiniert waren, geht an diesen Ort innerhalb der Datei und schreibt die Adresse, die an die Adresse gerufen wurde, einfach neu, also wenn wir vorher etwas in der Art hatten m1.o

call 0x000000 ;undefined goo address 

nach Symbol Lösung, Linker würden wahrscheinlich einige Einträge haben auf Relokationstabelle sagen Sie Schmiere-Adresse auf der Linie X verlagern müssen und wir werden

call 0x400100 ;actual goo address 

FYI in Folge, wenn ein nicht definiertes Referenzlinkerfehler aufweisen es bedeutet, dass Sie etwas nicht definiert Symbol in Ihrem Symboltabelle haben und der Linker kann eine passende Funktionsdefinition für sie nicht lösen ... auch wenn ich mich nicht klar gemacht habe, funktioniert das für globale und statische Variablen genauso, sie werden auch als Symbole betrachtet.

+0

Dies ist perfekt, Sie verdienen eine Medaille! Vielen Dank. – Pyjong