Domanda

Sono fermamente convinto dell'idea che una delle cose più importanti che si ottengono dall'apprendimento di una nuova lingua non sia come utilizzare una nuova lingua, ma la conoscenza dei concetti che si ottengono da essa. Non sto chiedendo quanto pensi sia importante o utile l'Assemblea, né mi interessa se non lo uso mai in nessuno dei miei progetti reali.

Quello che voglio sapere è quali concetti di Assembly ritieni siano più importanti da conoscere per qualsiasi programmatore generale? Non deve essere direttamente correlato ad Assembly: può anche essere qualcosa che ritieni che il tipico programmatore che trascorre tutto il suo tempo in linguaggi di livello superiore non capisca o dia per scontato, come la cache della CPU.

È stato utile?

Soluzione

Penso che il linguaggio dell'assemblaggio possa insegnarti molte piccole cose, così come alcuni grandi concetti.

Elencherò alcune cose a cui riesco a pensare qui, ma non vi è alcun sostituto per andare, imparare e usare sia x86 che un set di istruzioni RISC.

Probabilmente pensi che le operazioni su numeri interi siano più veloci. Se vuoi trovare una radice quadrata intera di un numero intero (es. Floor (sqrt (i))) è meglio usare una routine di approssimazione a numero intero, giusto?

Nah. Il coprocessore matematico (cioè su x86) ha un'istruzione fsqrt . La conversione in float, la radice quadrata e la conversione in int sono più veloci di un algoritmo a numeri interi.

Quindi ci sono cose come l'accesso alla memoria che puoi seguire, ma non apprezzare adeguatamente, fino a quando non hai approfondito l'assemblaggio. Supponi di avere un elenco collegato e che il primo elemento dell'elenco contenga una variabile alla quale dovrai accedere di frequente. L'elenco viene riordinato raramente. Bene, ogni volta che è necessario accedere a quella variabile, è necessario caricare il puntatore sul primo elemento nell'elenco, quindi utilizzarlo, caricare la variabile (supponendo che non sia possibile mantenere l'indirizzo della variabile in un registro tra gli usi) . Se invece hai memorizzato la variabile al di fuori dell'elenco, devi solo una singola operazione di caricamento.

Ovviamente salvare un paio di cicli qui e di solito non è importante in questi giorni. Ma se prevedi di scrivere codice che deve essere veloce, questo tipo di conoscenza può essere applicato sia con un assemblaggio in linea che generalmente in altre lingue.

Che ne dici di chiamare convenzioni? (Alcuni assemblatori si occupano di questo per te - I veri programmatori non li usano.) Il chiamante o il chiamante puliscono lo stack? Usi persino la pila? Puoi passare valori nei registri, ma a causa del divertente set di istruzioni x86, è meglio passare certe cose in determinati registri. E quali registri saranno conservati? Una cosa che i compilatori C non possono davvero ottimizzare da soli sono le chiamate.

Ci sono piccoli trucchi come PUSHing un indirizzo di ritorno e poi JMPing in una procedura; quando la procedura ritorna andrà all'indirizzo PUSHed. Questa deviazione dal solito modo di pensare alle chiamate di funzione è un altro di quegli "stati di illuminazione". Se dovessi progettare un linguaggio di programmazione con funzionalità innovative, dovresti conoscere cose divertenti di cui l'hardware è capace.

Una conoscenza del linguaggio assembly ti insegna cose specifiche dell'architettura sulla sicurezza del computer. Come sfruttare gli overflow del buffer o entrare nella modalità kernel e come prevenire tali attacchi.

Poi c'è l'eccessiva freddezza del codice auto-modificante e, come problema correlato, meccanismi per cose come il trasferimento e l'applicazione di patch al codice (questo richiede anche un'indagine sul codice macchina).

Ma tutte queste cose hanno bisogno del giusto tipo di mente. Se sei il tipo di persona che può mettere

while(x--)
{
  ...
}

a buon uso una volta appreso cosa fa, ma sarebbe difficile capire cosa fa da soli, quindi il linguaggio di assemblaggio è probabilmente una perdita di tempo.

Altri suggerimenti

Allocazione e gestione dei registri

Assembly ti dà un'ottima idea di quante variabili (numeri interi di dimensioni macchina) la CPU può destreggiarsi simultaneamente. Se riesci a spezzare i tuoi loop in modo che coinvolgano solo poche variabili temporanee, si adatteranno tutti ai registri. In caso contrario, il tuo ciclo verrà eseguito lentamente man mano che le cose vengono scambiate in memoria.

Questo mi ha davvero aiutato con la mia codifica C. Cerco di rendere tutti i loop stretti e semplici, con il minor numero di spaghetti possibile.

x86 è stupido

L'apprendimento di diverse lingue di assemblaggio mi ha fatto capire quanto sia scadente l'insieme di istruzioni x86. Istruzioni a lunghezza variabile? Tempi difficili da prevedere? Modalità di indirizzamento non ortogonale? Ugh.

Il mondo sarebbe migliore se tutti avessimo eseguito MIPS, penso, o addirittura ARM o PowerPC :-) O meglio, se Intel / AMD avesse preso la loro esperienza nei semiconduttori e lo avesse usato per creare multi-core, ultra-veloce, ultra - Procurati i processori MIPS anziché i processori x86 con tutte quelle qualità redentrici.

È utile conoscere il linguaggio assembly per ottenere un migliore apprezzamento del funzionamento del computer "sotto il cofano", " e aiuta quando si esegue il debug di qualcosa e tutto ciò che il debugger può darti è un elenco di codici assembly, che almeno ti dà la possibilità di combattere per capire quale potrebbe essere il problema. Tuttavia, provare ad applicare le conoscenze di basso livello ai linguaggi di programmazione di alto livello, come cercare di trarre vantaggio dal modo in cui la CPU memorizza nella cache le istruzioni e quindi scrivere un codice di alto livello per forzare il compilatore a produrre codice macchina super efficiente, è probabilmente un segno che stai provando a micro-ottimizzare. Nella maggior parte dei casi, di solito è meglio non provare a superare in astuzia il compilatore, a meno che non sia necessario il guadagno in termini di prestazioni, nel qual caso, è possibile anche scrivere quei bit nell'assembly.

Quindi, è bene conoscere l'assemblaggio per una migliore comprensione di come funzionano le cose, ma le conoscenze acquisite non sono necessariamente direttamente applicabili al modo in cui si scrive il codice in linguaggi di alto livello. In quella nota, tuttavia, ho scoperto che l'apprendimento di come funzionano le chiamate di funzione a livello di codice assembly (informazioni sullo stack e sui relativi registri, informazioni su come i parametri vengono passati sullo stack, informazioni su come funziona l'archiviazione automatica, ecc.) molto più facile da capire problemi che ho avuto nel codice di livello superiore, come "spazio di stack esaurito" errori e "convenzione di chiamata non valida" errori.

Il concetto più importante è SIMD e il suo uso creativo. L'uso corretto del SIMD può offrire enormi vantaggi in termini di prestazioni in una vasta gamma di applicazioni che vanno dall'elaborazione delle stringhe alla manipolazione video alla matematica matriciale. È qui che puoi superare aumenti delle prestazioni 10x su codice C puro - ecco perché l'assemblaggio è ancora utile al di là del semplice debug.

Alcuni esempi del progetto su cui lavoro (tutti i numeri sono conteggi del ciclo di clock su un Core 2):

DCT inverso 8x8 H.264 (trasformazione di frequenza):

c: 1332
mmx: 187
sse2: 127

Compensazione del movimento cromatico 8x8 (filtro interpolazione bilineare):

c: 639
mmx: 144
sse2: 110
ssse3: 79

4 operazioni di somma delle differenze assolute 16x16 (ricerca movimento):

c: 3948
mmx: 278
sse2: 231
ssse3: 215

(sì, esatto - oltre 18 volte più veloce di C!)

Errore quadratico medio di un blocco 16x16:

c: 1013
mmx: 193
sse2: 131

Varianza di un blocco 16x16:

c: 783
mmx: 171
sse2: 106

Memoria, registri, salti, loop, spostamenti e le varie operazioni che si possono eseguire in assembler. Non perdo i giorni in cui ho eseguito il debug dei programmi di classe di linguaggio assembly - sono stati dolorosi! - ma certamente mi ha dato una buona base.

Dimentichiamo (o non abbiamo mai saputo, forse) che tutta questa roba da pantalone che usiamo oggi (e che adoro!) si riduce a tutta questa roba alla fine.

Ora possiamo certamente avere una carriera produttiva e redditizia senza conoscere l'assemblatore, ma penso che questi concetti siano buoni da sapere.

Direi che l'apprendimento della ricorsione e dei cicli in assemblea mi hanno insegnato molto. Mi ha fatto capire il concetto alla base di come il compilatore / interprete della lingua che sto usando spinge le cose in una pila e le espelle quando ne ha bisogno. Ho anche imparato a sfruttare il famigerato overflow dello stack. (che è ancora sorprendentemente facile in C con alcuni comandi get e put).

Oltre a usare asm in situazioni quotidiane, non penso che userei nessuno dei concetti che mi hanno insegnato l'assemblea.

Direi che le modalità di indirizzamento sono estremamente importanti.

La mia alma mater l'ha portata all'estremo e poiché x86 non ne aveva abbastanza, abbiamo studiato tutto su un simulatore di PDP11 che deve averne almeno 7 che ricordo. Col senno di poi, è stata una buona scelta.

tempi

esecuzione veloce:

  • elaborazione parallela
  • istruzioni semplici
  • tabelle di ricerca
  • previsione del ramo, pipeline

accesso rapido per rallentare l'archiviazione:

  • registri
  • cache e vari livelli di cache
  • heap e stack di memoria
  • memoria virtuale
  • I / O esterno

Al giorno d'oggi, x86 asm non è una linea diretta con l'intestino della CPU, ma più di un'API. Gli opcode di assemblaggio che scrivi sono essi stessi compilati in un set di istruzioni completamente diverso, riorganizzati, riscritti, risolti e generalmente mutilati oltre il riconoscimento.

Quindi non è come l'apprendimento dell'assemblatore ti dà una visione fondamentale di ciò che accade all'interno della CPU. IMHO, più importante dell'apprendimento dell'assemblatore è capire bene come funzionano la CPU di destinazione e la gerarchia di memoria.

Questa serie di articoli tratta questo argomento in modo abbastanza approfondito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top