Quale conclusione si può trarre da nessuna differenza nell'assemblaggio generato da 2 programmi piuttosto diversi?

0

Potrei non aver avuto un controesempio quando ho ricevuto la risposta "Un puntatore è solo un indirizzo, qual è la difficoltà?" ma non ho davvero comprato una spiegazione così semplice e al codice assembly non è ovvio quale sia un puntatore per 2 diversi programmi C che generano lo stesso assembly.

 cat pelle.s valle.s 
    .file   "pelle.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    $0, %eax
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits
    .file   "valle.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    $0, %eax
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits

1) Un indirizzo di una variabile è &var1 e il puntatore è int* var1 scritto diversamente dall'indirizzo. 2) Quando compilo 2 programmi C in cui l'unica differenza è puntata, non c'è differenza nell'assembly:

$ diff pelle.c valle.c ;cat pelle.c valle.c;diff pelle.s valle.s 
3c3
< int * pelle;
---
>  int valle;
#include <stdio.h>
int main(void) {
int * pelle;
    return 0;
}
#include <stdio.h>
int main(void) {
 int valle;
    return 0;
}
1c1
<   .file   "pelle.c"
---
>   .file   "valle.c"

Ma quali conclusioni si possono trarre da nessuna differenza nell'assemblaggio generato per indagare sulla "differenza semplice ed evidente" tra una dichiarazione puntatore e un altro tipo? La risposta semplicistica va sempre avanti, un puntatore è solo una variabile e non ha senso in più analisi? O che la differenza tra un puntatore e una variabile è un caso di "zucchero" poiché i tipi vengono rimossi a livello di assemblaggio dove non c'è differenza? Una differenza nell'assembly generato mostrerà una diff se uso i puntatori come argomenti per una funzione e ci sarà davvero una differenza per l'uso di un puntatore e questo esempio è troppo banale e non può essere generalizzato? Quindi, quando i tipi vengono rimossi nell'assieme generato, posso concludere che la differenza di tipo in effetti risulterà in una differenza nell'assieme generato per un esempio non banale, ad es. puntatori come argomenti e questo esempio non è molto buono poiché sembra che l'assembly generato ignori la digitazione, mentre la differenza di tipo come questa farà la differenza nell'assemblaggio generato per un altro esempio?

int valle;
int * pelle;

 Assembler

.data
.align 2
.global valle
valle: .word 0

.data
.align 2
.global pelle
pelle: .word 0
    
posta Niklas Rosencrantz 12.04.2014 - 05:12
fonte

5 risposte

5

Producono lo stesso assembly perché il compilatore rimuove la variabile non utilizzata. Non contribuisce al codice, quindi non viene visualizzato nell'assembly. Potresti riuscire a vedere una differenza se disattivi tutte le ottimizzazioni.

Ma diamo un'occhiata all'assemblaggio dopo aver rimosso tutto cruft (numeri di riga aggiunti per semplificare la spiegazione):

1: main:
2:    pushl   %ebp
3:    movl    %esp, %ebp
4:    movl    $0, %eax
5:    popl    %ebp
6:    ret

Ciò che essenzialmente fa è impostare lo stack frame per una nuova funzione (riga 2 e 3), impostare il valore di ritorno su 0 (riga 4) e ripristinare il frame dello stack e tornare dalla funzione (righe 5 e 6 ).

Questo si traduce nel seguente codice C:

int main(void)
{
    return 0;
}

Che è esattamente ciò che il compilatore vede dopo aver rimosso la variabile che non viene utilizzata.

Quindi, in breve, la conclusione è che l'assembly è lo stesso perché i programmi sono gli stessi . Il fatto che dichiari una variabile locale che non contribuisce al programma non ne fa un programma diverso.

    
risposta data 12.04.2014 - 11:43
fonte
2

L'unica conclusione assoluta che puoi trarre è che i due programmi si comportano lo stesso se sono stati compilati con lo stesso compilatore per la stessa piattaforma di destinazione.

Se poi analizzi le differenze nel codice sorgente, potresti anche essere in grado di dedurre che ci sono similitudini / equivalenze semantiche .

In effetti, è molto probabile che ci saranno equivalenze semantiche a livello di codice sorgente ... anche se possono dipendere da ipotesi non portabili nel codice; per esempio. che int e int* hanno la stessa dimensione.

    
risposta data 12.04.2014 - 05:40
fonte
1

Il fatto che due programmi vengano compilati con lo stesso codice assembly significa che i due programmi producono lo stesso comportamento. Le differenze nei programmi che non contribuiscono al comportamento (come le variabili inutilizzate nei tuoi esempi) possono o non possono essere visualizzate nel codice assembly. Il compilatore ha tutti i suoi diritti per eliminare completamente queste parti.

I linguaggi di assemblaggio non sono tipizzati, il che significa che il concetto di tipi non esiste nell'assemblaggio. Il concetto di un tipo è un concetto di livello superiore che limita ciò che puoi fare con una variabile.

Nel linguaggio assembly, una variabile non è altro che un pezzo di memoria o un registro che è stato messo da parte per uno scopo particolare (dove tale scopo è determinato dal programmatore). L'assemblatore ti consentirà di eseguire qualsiasi operazione nota su una variabile ed è tua responsabilità assicurarti che l'operazione abbia senso.

Nei linguaggi di livello superiore che hanno il concetto di tipi, informi il compilatore come intendi utilizzare una variabile ("Intendo usare valle come posizione per i numeri e pelle come posizione per gli indirizzi di variabili intere ") e il compilatore assume parte del carico per garantire che le operazioni eseguite con una variabile abbiano senso.

Durante la compilazione di un linguaggio di livello superiore, il compilatore controlla che le regole di tipo siano rispettate dal programma, ma getta via le informazioni sul tipo dopo questo perché non c'è modo di tenerlo in assembly o linguaggio macchina.
Durante la lettura dell'assieme, l'unico modo per ricavare informazioni sul tipo è osservare come vengono utilizzate le variabili nell'assieme generato. E anche in questo caso, le informazioni sul tipo dedotto potrebbero essere incomplete.

    
risposta data 12.04.2014 - 10:11
fonte
0

Se i due programmi generano lo stesso assembly, allora puoi essere certo che se assemblati usando lo stesso assemblatore, quelli produrranno lo stesso codice macchina. E questo è tutto.

Ma se quello fosse l'unico punto, allora staremmo tutti codificando in assemblea. I linguaggi di programmazione riguardano le astrazioni. Questo è letteralmente il punto.

In C, i puntatori fanno parte di quell'astrazione, ma c'è più di un modo per ottenere lo stesso risultato. Il risultato che ottieni non è il modo in cui misuri il valore dell'astrazione, ma è la base su cui è costruita l'astrazione.

Ciò che conta è il modo in cui una determinata lingua rende il codice più facile da ragionare, più facile da evitare errori, più facile da comunicare agli altri. E se questo non è il tuo obiettivo, allora potresti scrivere il tuo codice in assembly.

    
risposta data 12.04.2014 - 08:47
fonte
0

La tua domanda è piuttosto difficile da seguire e non sono sicuro di quale problema tu voglia rispondere. Il mio contributo è sottolineare che

  • a livello di linguaggio assembly, non c'è assolutamente alcuna differenza tra un puntatore e un valore, ed entrambi possono essere archiviati in memoria o caricati in un registro
  • a livello di un linguaggio simile a C viene fatta una distinzione tra puntatori e valori in modo che il compilatore possa aiutarti a usarli correttamente
  • a livello di un linguaggio di livello superiore non ci sono puntatori, solo valori e riferimenti.

Lo scopo principale di un linguaggio di livello superiore e il compilatore che lo supporta è quello di liberarti dal pensare ai dettagli del livello della macchina. I puntatori sono un tale dettaglio, non fanno parte della soluzione per qualsiasi problema di elaborazione ma solo parte dei dettagli di implementazione del programma che esegue la soluzione.

    
risposta data 12.04.2014 - 12:16
fonte

Leggi altre domande sui tag