2016-04-30 18 views
8

Questo è il mio programma in C usando puts():Qual è la differenza tra put e printf in C compilato in linguaggio Assembly

#include <stdio.h> 
int main(void){ 
puts("testing"); 
} 

Dopo aver utilizzato gcc -S -o sample.s sample.c a compilato in Assemblea, questo è quello che ho ottenuto:

 .file "sample.c" 
     .section  .rodata 
.LC0: 
     .string "testing" 
     .text 
.globl main 
     .type main, @function 
main: 
     pushl %ebp 
     movl %esp, %ebp 
     andl $-16, %esp 
     subl $16, %esp 
     movl $.LC0, (%esp) 
     call puts 
     leave 
     ret 
     .size main, .-main 
     .ident "GCC: (GNU) 4.4.5 20110214 (Red Hat 4.4.5-6)" 
     .section  .note.GNU-stack,"",@progbits 

ho fatto lo stesso modo in cui, questa volta stavo usando printf() invece degli attuali e questo è quello che ho ottenuto:

.file "sample.c" 
     .section  .rodata 
.LC0: 
     .string "testing" 
     .text 
.globl main 
     .type main, @function 
main: 
     pushl %ebp 
     movl %esp, %ebp 
     andl $-16, %esp 
     subl $16, %esp 
     movl $.LC0, %eax  //this is the difference 
     movl %eax, (%esp) 
     call printf 
     leave 
     ret 
     .size main, .-main 
     .ident "GCC: (GNU) 4.4.5 20110214 (Red Hat 4.4.5-6)" 
     .section  .note.GNU-stack,"",@progbits 

Ecco quello che non capisco, la funzione printf()mov $.LC0-%eax, poi mov %eax-(%esp) mentre la funzione mov %.LC0puts() direttamente a (%esp). Non so perché sia ​​così.

+6

Probabilmente è perché 'printf' è una funzione varargs, e ottengono chiamato in modo diverso dalle funzioni che hanno un numero fisso di argomenti. – Barmar

+1

È interessante notare che, usando clang su os x, entrambi i programmi vengono compilati nello stesso assembly. – Leandros

+0

Anche perché GCC sta compilando il codice dipendente dalla posizione su linux? – Leandros

risposta

4

La grande differenza tra le due funzioni, a livello di assieme, è che la funzione puts() prende solo un argomento (un puntatore alla stringa da visualizzare) e la funzione printf() accetta un argomento (un puntatore al formato stringa) e, quindi, un numero arbitrario di argomenti nello stack (printf() è una funzione variadica).

Si noti che, non vi è assolutamente alcuna verifica del numero di argomenti, è solo in funzione del numero di volte in cui si incontra il carattere % nella stringa di formato. Ad esempio, questa specificità viene utilizzata nel metodo di sfruttamento dei bug in formato stringa per esplorare in modo interattivo il contenuto della pila di un processo.

Quindi, fondamentalmente, la differenza è che puts() ha un solo argomento e printf() è una funzione variadica.

Se si vuole comprendere meglio questa differenza, provare a compilare:

#include <stdio.h> 

int main(void) { 
    printf("testing %d", 10); 
} 
+1

Vale anche la pena ricordare che 'puts' aggiunge un' \ n' implicitamente, a differenza di 'fputs'.Vedi anche [due casi in cui il compilatore ottimizza printf to puts e due casi in cui non lo fa] (https://godbolt.org/g/w2d2fI). E http://stackoverflow.com/questions/36343733/o2-optimizes-printfs-n-str-to-putsstr. –