2014-09-12 9 views
10

Il seguente codice assembly genera un errore durante l'esecuzione di as su OSX 10.9.4, ma funziona correttamente su Linux (Debian 7.6). In particolare, l'istruzione movq non sembra gradire l'argomento dell'etichetta.Perché questa istruzione movq funziona su linux e non su osx?

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

Ecco l'errore:

$ 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 

Modifica $_main in linea di 3 ad un letterale come $10 funziona bene.

Il codice doveva essere modificato in un modo molto minore per farlo funzionare su Linux - semplicemente rimuovendo i caratteri di sottolineatura dalle etichette.

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

E 'abbastanza facile da verificare in modo indipendente che il codice funziona su Linux:

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

Si prega di ignorare che il codice in realtà non fare molto di nulla, ho volutamente rifilato giù come il più possibile per dimostrare l'errore.

Ho guardato un bel po 'a usare LEA (caricare l'indirizzo effettivo), ma prima di apportare questa modifica mi piacerebbe capire la differenza - perché funziona su Linux e non su OSX?

+1

+1 domanda ben scritto con un ottimo minimal, completo, esempio di codice verificabile – msw

risposta

8

Si è corretto sull'istruzione movq che non è in grado di fare riferimento all'indirizzo assoluto. Ciò è in parte dovuto al formato OS X ABI Mach-O che utilizza l'indirizzamento rilocabile per i simboli.

Un programma compilato come eseguibile indipendente dalla posizione (PIE) in genere non può fare riferimento a un indirizzo virtuale assoluto nello stesso modo di movq $_main, %rax. Invece, vengono chiamati Global Offset Tables, che consentono il codice relativo alla posizione (PC-rel) e il codice indipendente dalla posizione (PIC) per estrarre simboli globali nella posizione corrente dell'indirizzo corrente. Tabella

codice PC-rel riferimento è Offset globale:: dimostrato di seguito, GOTPCREL(%rip) crea un'interpretazione del lea rdi, _msg

.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 

Versione di GCC di Apple:

$ gcc -o test.out test.o 

uscita:

$ ./test.out 
Hello, world 
+1

Questo è straordinariamente disponibile, e ci tornerò sicuramente accettare la risposta. Ma, mi chiedo se puoi spiegare cosa succede su Linux? Anche se credo che la risposta sia piuttosto semplice: usa l'indirizzamento assoluto? Comunque (e forse sono confuso, e forse questo merita la sua domanda di follow-up), ho pensato che l'indirizzamento rilocabile fosse richiesto in e/o fondamentale per x86-64. –

+0

L'esempio di Linux può sembrare che usi l'indirizzamento assoluto, tuttavia le istruzioni come '$ main,% rax' vengono automaticamente convertite in' GOTPCREL' e utilizzano la rispettiva tabella di offset globale. La tabella Linkage della procedura (PLT) - il meccanismo che determina l'indirizzo assoluto di una funzione in fase di esecuzione differisce anche un po '. Le voci PLL ELF sono organizzate e raggruppate in blocchi identificati dalla loro sezione 'plt'. Con Mach-O il PLT è unito a più sezioni, chiamate 'stub helper', e richiedono un passo in più per trovare l'id corrispondente. –

+1

La bellezza dell'utilizzo coerente di 'GOTPCREL' per i programmi destinati sia a Linux che a OS X è che consente di risparmiare un sacco di tempo; perché tutto ciò che deve essere modificato è aggiungere caratteri di sottolineatura ai simboli o rimuoverli. [Questo esempio] (https://gist.github.com/anonymous/8fa1fe6586589995b35d) dimostra un codice Linux/OS X quasi identico che utilizza questo principio. –

Problemi correlati