Beim Studieren von Assembler bin ich auf diese Begriffe gestoßen. Die Idee, die ich bekommen habe, ist wie folgt: In relocatable machine code ist der Code nicht von statischem RAM abhängig. Der Assembler gibt den RAM-Bedarf für mein Programm an. Der Speicher kann überall dort platziert werden, wo der Linker Platz findet.
Stimmt die Idee? Wenn ja, wie wird es vom Assembler gemacht?
Und, was sind einige Beispiele für Absolute Machine Code?
Viele / die meisten Befehlssätze haben eine relative PC-Adressierung, dh nehmen die Adresse des Programmzählers, die mit der Adresse der ausgeführten Anweisung zusammenhängt, und fügen dann einen Offset hinzu und verwenden diesen für den Zugriff auf Speicher oder Verzweigungen oder etwas ähnliches. das wäre das, was du als verlagerbar bezeichnen würdest. Denn unabhängig davon, wo sich diese Anweisung im Adressraum befindet, ist die Sache, zu der Sie springen möchten, relativ. Verschieben Sie den gesamten Codeblock und die Daten an eine andere Adresse, und sie haben immer noch den gleichen Abstand, so dass die relative Adressierung weiterhin funktioniert. Bei gleichem Überspringen funktioniert der nächste Befehl, wo auch immer diese drei Befehle sind (das if-Überspringen, das Überspringen und das Überspringen).
Absolut verwendet absolute Adressen, springt zu dieser genauen Adresse, liest von dieser genauen Adresse. Wenn gleich, verzweige zu 0x1000.
Der Assembler tut dies nicht den Compiler und / oder Programmierer. Im Allgemeinen wird kompilierter Code schließlich eine absolute Adressierung haben, insbesondere wenn Ihr Code aus separaten Objekten besteht, die miteinander verknüpft sind. Zur Kompilierzeit kann der Compiler nicht wissen, wo das Objekt enden wird, und es ist nicht möglich zu wissen, wo die externen Referenzen sind oder wie weit entfernt, so dass sie im Allgemeinen nicht nahe genug für die pc-relative Adressierung sein können (was normalerweise eine Bereichsgrenze hat) . Daher erzeugen die Compiler oft einen Platzhalter, damit der Linker eine absolute Adresse eingibt. Es hängt von der Operation und dem Befehlssatz und einigen anderen Faktoren ab, wie dieses externe Adressenproblem gelöst wird. Letztendlich wird der Linker jedoch basierend auf der Projektgröße mit einer absoluten Adressierung enden. Der Nicht-Standard ist also normalerweise eine Befehlszeilenoption, um positionsunabhängigen Code zu erzeugen. PIC könnte beispielsweise etwas sein, das Ihr Compiler unterstützt. Sowohl der Compiler als auch der Linker müssen dann zusätzliche Arbeit leisten, um diese Elemente positionsunabhängig zu machen. Ein Assembler-Programmierer muss das alles selbst machen, der Assembler wird im Allgemeinen nicht damit beschäftigt, sondern er erstellt nur den Maschinencode für die Anweisungen, die Sie ihm mitteilen.
novectors.s:
%Vor%Hallo.c
%Vor%memap (das Linker-Skript) ERINNERUNG { RAM: ORIGIN = 0xD6000000, LÄNGE = 0x4000 } Abschnitte { .text: { (. text )} & gt; RAM } Makefile
%Vor%hallo_world.list (die Teile, die uns interessieren)
%Vor%Was ich hier zeige, ist eine Mischung aus positionsunabhängigen Anweisungen und positionsabhängigen Anweisungen.
Diese beiden Anweisungen sind zum Beispiel eine Verknüpfung, um den Assembler zu zwingen, einen .word-Stil-Speicherort hinzuzufügen, den der Linker dann für uns ausfüllen muss.
%Vor%0xD600001c ist dieser Ort.
%Vor%und es ist mit der Adresse 0xD6000020 ausgefüllt, die eine absolute Adresse ist, damit der Code funktioniert, muss die Funktion notmain an der Adresse 0xD6000020 sein, die nicht verschoben werden kann. aber dieser Teil des Beispiels zeigt auch einen positionsunabhängigen Code, das
%Vor%ist die pc relative Adressierung Ich sprach über die Art und Weise, wie dieser Befehlssatz arbeitet, zum Zeitpunkt der Ausführung ist der PC zwei Anweisungen voraus oder grundsätzlich in diesem Fall, wenn der Befehl bei 0xD600000c im Speicher ist, dann wird der pc 0xD6000014 sein Ausführen dann 8 hinzufügen, wie der Befehl angibt, und Sie erhalten 0xD600001C. Aber wenn wir genau die gleiche Maschinencode-Anweisung zu Adresse 0x1000 AND verschoben haben, bewegen wir alle umgebenden Binärdateien dorthin, einschließlich der Sache, die sie liest (die 0xD6000020). Mach das grundsätzlich:
%Vor%Und diese Anweisungen, dieser Maschinencode wird immer noch funktionieren, er muss nicht neu zusammengesetzt oder neu verknüpft werden. die 0xD6000020 Code-Datei muss an dieser festen Adresse sein, die den ldr pc und blx dont.
Obwohl der Disassembler diese mit 0xd6 ... basierten Adressen anzeigt, sind die bl und bne auch pc relativ, was Sie anhand der Dokumentation des Befehlssatzes herausfinden können
%Vor%0xD6000030 würde einen PC von 0xD6000038 haben, wenn er ausgeführt wird und 0xD6000038-0xD6000018 = 0x20, was 8 Anweisungen ist. Und eine negative 8 in Zweierkomplement ist 0xFFF..FFFF8, können Sie sehen, der Großteil dieser Maschinencode ebfffff8 ist ffff8, das ist, was Zeichen erweitert und dem Programmzähler hinzugefügt, um im Grunde sagen Verzweigung zurück 8 Anweisungen. Das gleiche gilt für die ffffa in 1afffffa bedeutet, wenn nicht gleich dann Verzweigung zurück 6 Anweisungen. Denken Sie daran, dass dieser Befehlssatz (Arm) davon ausgeht, dass der PC zwei Anweisungen voraus ist, so dass Rückseite 6 vorwärts zwei dann zurück 6 oder effektiv zurück 4 bedeutet.
Wenn Sie das
entfernen %Vor%Dann endet dieses ganze Programm mit der Position unabhängig, zufällig (ich habe zufällig gewusst, dass es passieren würde), aber nicht, weil ich den Tools gesagt habe, nur weil ich alles nah gemacht habe und kein absolutes verwendet habe Adressierung.
Schließlich, wenn Sie sagen "wo der Linker Platz für sie findet" wenn Sie in meinem Linker-Skript merke ich dem Linker alles ab 0xD6000000 zu setzen, habe ich keine Dateinamen oder Funktionen angegeben, wenn nicht anders angegeben, diese Linker platziert die Elemente in der Reihenfolge, in der sie in der Befehlszeile angegeben sind. Der Code hello.c ist der zweite, also nachdem der Linker den Code novectors.s platziert hat, beginnt der Code hello.c, wo auch immer der Linker Platz hatte, gleich bei 0xD6000020.
Und eine einfache Möglichkeit zu sehen, was positionsunabhängig ist und was nicht, ohne jede Anweisung zu untersuchen, wäre, das Linker-Skript zu ändern, um den Code an eine andere Adresse zu setzen.
%Vor%und sehen, welcher Maschinencode sich ändert, wenn und welcher nicht.
%Vor%Alles, was tatsächlich eine Adresse innerhalb des Codes enthält, hat eine absolute Adresse. Programme, die keine Adressen innerhalb des Codes enthalten (alles wird mit relativen Adressen gemacht) können von jeder Adresse aus ausgeführt werden.
Der Assembler macht das nicht, der Programmierer tut es. Ich habe in der Vergangenheit ein bisschen davon gemacht, für kleine Sachen ist es normalerweise einfach, sobald man über den Bereich eines relativen Sprunges hinausgeht, wird es ziemlich schmerzhaft. IIRC die einzigen beiden Ansätze sind, relative Sprünge zwischen Routinen zu gleiten oder einen bekannten Offset zur aktuellen Adresse hinzuzufügen, ihn zu drücken und dann zurückzukehren. Früher gab es einen dritten Ansatz, es zu berechnen und in den Code zu schreiben, aber das ist nicht mehr akzeptabel. Es ist lange genug, dass ich nicht schwöre, dass es keine anderen Ansätze gibt.
IIRC die einzige Möglichkeit, etwas ohne absolute Adressen "aufzurufen", ist, die Adresse, zu der Sie zurückkehren möchten, zu drücken, die Adresse zu berechnen, sie zu drücken und zurückzukehren.
Beachten Sie, dass Sie in der Praxis normalerweise einen hybriden Ansatz verwenden. Der Assembler und der Linker speichern die Informationen, die zum Durchführen der Anpassungen erforderlich sind, wenn das Programm in den Speicher geladen wird, der so geändert wird, dass es unter der Adresse ausgeführt wird, unter der es geladen wurde. Das tatsächliche Bild im Speicher ist somit absolut, aber die Datei auf der Festplatte funktioniert wie relativ, aber ohne all die Kopfschmerzen, die normalerweise entstehen. (Beachten Sie, dass derselbe Ansatz bei allen höheren Sprachen verwendet wird, die nativen Code tatsächlich erzeugen.)
Grundsätzlich bedeutet "absoluter" Modus, dass die Code- und RAM-Variablen genau dort platziert werden, wo Sie dem Assembler sagen, während "replaceatable" bedeutet, dass der Assembler Code-Chunks erstellt und RAM-Anforderungen spezifiziert, die überall platziert werden können findet Platz für sie.
Ich bin mir nicht sicher, ob die angenommene Antwort hier richtig ist. Es besteht ein grundlegender Unterschied zwischen dem verschiebbaren Code und dem positionsunabhängigen Code.
Jetzt habe ich die Assemblierung lange Zeit und auf vielen verschiedenen Architekturen programmiert, und ich habe immer daran gedacht, dass Maschinencode in drei spezifischen Geschmacksrichtungen vorkommt: -
Lassen Sie uns zuerst den positionsunabhängigen -Code besprechen. Dies ist ein Code, der, wenn er zusammengesetzt ist, alle seine Anweisungen relativ zueinander hat. So spezifizieren Verzweigungen zum Beispiel einen Offset von dem aktuellen Anweisungszeiger (oder Programmzähler, wie immer man ihn nennen will). Code, der positionsunabhängig ist, besteht nur aus einem Codeabschnitt und seine Daten sind auch in diesem Segment (oder Abschnitt) enthalten. Es gibt Ausnahmen für Daten, die in dasselbe Segment eingebettet werden, aber diese Vorteile werden normalerweise vom Betriebssystem oder vom Loader übernommen.
Das ist eine sehr nützliche Art von Code, weil das Betriebssystem keine Nachladeoperationen ausführen muss, um mit der Ausführung beginnen zu können. Es wird einfach überall ausgeführt, wo es im Speicher geladen wird. Natürlich hat diese Art von Code auch seine Probleme, nämlich Dinge, die nicht in der Lage sind, Code und Daten zu trennen, die für unterschiedliche Speichertypen und Größenbeschränkungen geeignet sind, bevor Angehörige sich außerhalb des Bereichs bewegen, um nur einige zu nennen / p>
Relocatable-Code ähnelt in vielerlei Hinsicht positionsunabhängigem Code, hat aber einen sehr feinen Unterschied. Wie der Name schon andeutet, ist diese Art von Code verschiebbar, da der Code irgendwo in den Speicher geladen werden kann, aber normalerweise verschoben oder repariert wird, bevor er ausführbar ist. Tatsächlich enthalten einige Architekturen, die diese Art von Code verwenden, Dinge wie "Verlagerung" -Bereiche zu diesem Zweck, um die verschiebbaren Teile des Codes zu reparieren. Der Nachteil dieser Art von Code ist, dass sobald es verschoben und repariert wird, wird es fast absolut in der Natur und fixiert auf seine Adresse.
Was einen verschiebbaren Code zu seinem Hauptvorteil macht und der häufigste Code dafür ist, dass Code leicht in Abschnitte zerlegt werden kann. Jeder Abschnitt kann an beliebiger Stelle in den Speicher geladen werden, um seinen Anforderungen gerecht zu werden, und dann kann jeder Code, der auf einen anderen Abschnitt verweist, während des Verschiebens mit einer Verschiebungstabelle repariert werden, und die Abschnitte können somit gut miteinander verbunden werden. Der Code selbst ist normalerweise relativ (wie bei der x86-Architektur), muss aber nicht sein, da alles, was außerhalb der Reichweite liegt, als eine verschiebbare Anweisung zusammengesetzt werden kann, so dass sie aus einem Offset besteht, der zu ihrer Ladeadresse hinzugefügt wird. Es bedeutet auch, dass Beschränkungen durch relative Adressierung kein Problem mehr sind.
Die letzte Art von Code ist Absolute-Code . Dieser Code ist so zusammengestellt, dass er an einer bestimmten Adresse funktioniert und funktioniert nur, wenn er an dieser Adresse geladen wird. only Verzweigungs- und Sprunganweisungen enthalten alle eine feste exakte (absolute) Adresse. Es ist eine Art von Code, der normalerweise auf eingebetteten Systemen gefunden wird, wobei garantiert werden kann, dass ein Codeabschnitt an dieser spezifischen Adresse geladen wird, da es das einzige ist, das dort geladen wird. Auf einem modernen Computer würde ein solcher absoluter Code nicht funktionieren, da Code überall dort geladen werden muss, wo freier Speicher vorhanden ist, und es gibt niemals eine Garantie, dass ein bestimmter Speicherbereich verfügbar sein wird. Absoluter Code hat jedoch seine Vorteile, hauptsächlich weil er im Allgemeinen am schnellsten ausgeführt wird, aber dies kann plattformabhängig sein.
"relocatable" bedeutet, dass der Assembler Code-Chunks erstellt und RAM-Anforderungen festlegt, die überall dort platziert werden können, wo der Linker Platz findet.
Tags und Links assembly relocation