2011-12-11 11 views
5

Sto provando a definire alcune subroutine che hanno chiamate a printf in esse. Un esempio molto banale è il seguente:vengono richiamate due volte senza nemmeno essere chiamate dal principale

extern printf 
LINUX  equ  80H 
EXIT   equ  60 

section .data 
    intfmt: db "%ld", 10, 0 

segment .text 
    global main 

main: 
    call os_return  ; return to operating system 

os_return: 
    mov rax, EXIT  ; Linux system call 60 i.e. exit() 
    mov rdi, 0  ; Error code 0 i.e. no errors 
    int LINUX  ; Interrupt Linux kernel 

test: 
    push rdi 
    push rsi 
    mov rsi, 10 
    mov rdi, intfmt 
    xor rax, rax 
    call printf 
    pop rdi 
    pop rsi 
    ret 

Qui test ha solo una chiamata a printf che emette il numero 10 allo schermo. Non mi aspetterei che venga chiamato perché non ho nessuna chiamata.

Tuttavia durante la compilazione e l'esecuzione:

nasm -f elf64 test.asm 
gcc -m64 -o test test.o 

ottengo l'output:

10 
10 

Sono totalmente sconcertato e mi chiedevo se qualcuno potrebbe spiegare perché questo sta accadendo?

risposta

3

int 80H richiama l'interfaccia di chiamata di sistema a 32 bit, che a) utilizza i numeri di chiamata di sistema a 32 bit eb) è destinata all'uso da codice a 32 bit, non a 64 bit. Il tuo codice esegue effettivamente una chiamata di sistema umask con parametri casuali.

Per una chiamata di sistema a 64 bit, utilizzare l'istruzione syscall invece:

... 
os_return: 
    mov rax, EXIT  ; Linux system call 60 i.e. exit() 
    mov rdi, 0  ; Error code 0 i.e. no errors 
    syscall   ; Interrupt Linux kernel 
... 
+0

Grazie! Metto il valore 60 (EXIT) in rdi allora invece di rax, come chiamare printf? –

+0

No, inserendo il numero di syscall in 'rax' e il primo argomento in' rdi' è corretto. Si veda http://www.x86-64.org/documentation/abi.pdf (appendice A in particolare) per la documentazione dell'ABI del kernel syscall e le differenze dalle convenzioni di chiamata a livello utente. –

+0

Mi spiace continuare a tormentarti su questo, ma ho cambiato la riga "int LINUX" per chiamare syscall e aggiunto extern syscall verso l'alto e ottenere ancora i due dieci. C'è qualche possibilità che tu possa mostrarmi un mini esempio di come chiamare syscall? Grazie mille :) –

2

Direi che la chiamata a exit sta fallendo, così quando si torna, si cade attraverso la funzione test, che stampa il primo 10.

Poi quando si torna con ret si torna alle istruzioni subito dopo lo call os_return, ovvero, os_return. La chiamata per uscire fallisce nuovamente e ricade nuovamente nella funzione test. Ma questa volta il ret ritorna dalla funzione main e il programma termina.

Informazioni sul motivo per cui la chiamata exit non riesce, non posso dire perché non ho un sistema a 64 bit disponibile. Ma potresti smontare la funzione exit da libc e vedere come è fatta lì. La mia ipotesi è che l'interfaccia sia solo a 32 bit, in quanto esiste solo per compatibilità storica e Linux a 64 bit non così vecchia.