2014-09-12 11 views
10

Der folgende Assembly-Code gibt einen Fehler beim Ausführen von as unter OSX 10.9.4, funktioniert aber erfolgreich unter Linux (Debian 7.6). Insbesondere scheint die movq-Anweisung das Label-Argument nicht zu mögen. HierWarum funktioniert diese movq-Anweisung auf Linux und nicht auf osx?

$ cat test.S 
.globl _main 
_main: 
    movq $_main, %rax 
    ret 

ist der Fehler:

$ as -o test.o test.S 
test.S:3:32-bit absolute addressing is not supported for x86-64 
test.S:3:cannot do signed 4 byte relocation 

Ändern $_main in Zeile 3 zu einer wörtlichen wie $10 funktioniert gut.

Der Code musste sehr geringfügig geändert werden, damit er unter Linux ausgeführt werden konnte - indem einfach die Unterstriche von den Beschriftungen entfernt wurden.

$ cat test.S 
.globl main 
main: 
    movq $main, %rax 
    ret 

es ziemlich einfach ist, unabhängig zu überprüfen, ob der Code auf Linux funktioniert:

$ as -o test.o test.S 
$ gcc -o test.out test.o 
$ ./test.out 

Bitte ignorieren, dass der Code wirklich viel tun, nicht von etwas, habe ich getrimmt es absichtlich nach unten als so viel wie möglich, um den Fehler zu demonstrieren.

Ich habe ziemlich viel in die Verwendung von LEA (Load Effective Address) geschaut, aber bevor ich diese Änderung mache, möchte ich den Unterschied verstehen - warum funktioniert es unter Linux und nicht unter OSX?

+1

+1 gut schriftliche Anfrage mit einem sehr guten minimal, vollständigen, überprüfbaren Codeb. – msw

Antwort

8

Sie haben die Anweisung movq richtig gelesen, die absolute Adresse nicht referenzieren zu können. Dies ist teilweise auf das Format OS X ABI Mach-O zurückzuführen, das eine verschiebbare Adressierung für Symbole verwendet.

Ein Programm, das als positionsunabhängige ausführbare Datei kompiliert wird (PIE), kann in der Regel keine absolute virtuelle Adresse referenzieren wie movq $_main, %rax. Stattdessen werden Global Offset Tables aufgerufen, die es dem relativen Positionscode (PC-rel) und dem positionsunabhängigen Code (PIC) ermöglichen, globale Symbole an ihrer aktuellen absoluten Adresse zu extrahieren. Nachgewiesene unten, GOTPCREL(%rip) schafft eine Interpretation des lea rdi, _msg:

PC-rel Code es globale Offset-Tabelle verweisen:

.globl _main 
_main: 

    movq  [email protected](%rip), %rax 
    sub  $8, %rsp 
    mov  $0, %rax 
    movq  [email protected](%rip), %rdi 
    call  _printf 
    add  $8, %rsp 
    ret 

.cstring 
_msg: 

    .ascii "Hello, world\n" 

Mac OS X Mach-O Assembler:

$ as -o test.o test.asm 

Apples Version von GCC:

$ gcc -o test.out test.o 

Ausgang:

$ ./test.out 
Hello, world 
+1

Das ist wunderbar hilfreich, und ich werde auf jeden Fall die Antwort akzeptieren. Aber ich frage mich, ob Sie erklären können, was auf Linux passiert? Obwohl ich denke, die Antwort ist ziemlich einfach: Es verwendet absolute Adressierung? Allerdings (und vielleicht bin ich verwirrt, und vielleicht verdient dies seine eigene Follow-up-Frage), dachte ich, dass umsetzbare Adressierung in und/oder grundlegend für x86-64 erforderlich war. –

+0

Das Linux-Beispiel scheint die absolute Adressierung zu verwenden, die Anweisungen wie $ main,% rax werden jedoch automatisch in 'GOTPCREL' übersetzt und verwenden ihre entsprechende globale Offset-Tabelle. Die Prozedur-Verknüpfungstabelle (PLT) - der Mechanismus, der die absolute Adresse einer Funktion zur Laufzeit bestimmt, unterscheidet sich ebenfalls ein wenig. ELF-PLT-Einträge sind organisiert und in Gruppen gruppiert, die durch ihren eigenen "plt" -Abschnitt identifiziert werden. Mit Mach-O wird der PLT über mehrere Abschnitte, die als "Stub-Helfer" bezeichnet werden, gespleißt und erfordert einen zusätzlichen Schritt, um eine entsprechende Symbol-ID zu finden. –

+1

Die Schönheit der konsequenten Verwendung von 'GOTPCREL' für Programme, die sowohl für Linux als auch für OS X gedacht sind, ist, dass es eine Menge Zeit spart; Für alles, was geändert werden muss, fügen Sie den Symbolen Unterstriche hinzu oder entfernen sie. [Dieses Beispiel] (https://gist.github.com/anonymous/8fa1fe6586589995b35d) demonstriert nahezu identischen Linux/OS X-Code mit diesem Prinzip. –