Ricerca…


Osservazioni

L'assemblaggio in linea è la pratica di aggiungere istruzioni di assemblaggio nel mezzo del codice sorgente C. Nessuno standard ISO C richiede il supporto del montaggio in linea. Poiché non è richiesto, la sintassi per l'assembly in linea varia dal compilatore al compilatore. Anche se in genere è supportato, esistono pochissimi motivi per utilizzare l'assembly inline e molte ragioni per non farlo.

Professionisti

  1. Prestazioni Scrivendo le istruzioni di assemblaggio specifiche per un'operazione, è possibile ottenere prestazioni migliori rispetto al codice assembly generato dal compilatore. Si noti che questi miglioramenti delle prestazioni sono rari. Nella maggior parte dei casi è possibile ottenere un miglioramento delle prestazioni semplicemente riorganizzando il codice C in modo che l'ottimizzatore possa svolgere il proprio lavoro.
  2. Interfaccia hardware Per il codice di avvio del driver o del processore del dispositivo potrebbe essere necessario un codice di assembly per accedere ai registri corretti e per garantire che determinate operazioni si verifichino in un ordine specifico con uno specifico ritardo tra le operazioni.

Contro

  1. La sintassi di portabilità del compilatore per l'assemblaggio in linea non è garantita per essere uguale da un compilatore all'altro. Se si sta scrivendo un codice con un assembly inline che deve essere supportato da compilatori diversi, utilizzare le macro del preprocessore ( #ifdef ) per controllare quale compilatore viene utilizzato. Quindi, scrivi una sezione di assembly inline separata per ciascun compilatore supportato.
  2. Portabilità del processore Non è possibile scrivere assembly in linea per un processore x86 e aspettarsi che funzioni su un processore ARM. L'assembly in linea è progettato per essere scritto per un processore specifico o una famiglia di processori. Se si dispone di un assembly in linea che si desidera supportare su processori diversi, utilizzare le macro del preprocessore per verificare quale processore viene compilato il codice e per selezionare la sezione del codice assembly appropriata.
  3. Modifiche prestazionali future L' assemblaggio in linea può essere scritto in attesa di ritardi basati su una determinata velocità di clock del processore. Se il programma è compilato per un processore con un clock più veloce, il codice assembly potrebbe non funzionare come previsto.

gcc Supporto di base asm

Il supporto dell'assembly di base con gcc ha la seguente sintassi:

asm [ volatile ] ( AssemblerInstructions )

dove AssemblerInstructions è il codice di assemblaggio diretto per il processore specificato. La parola chiave volatile è facoltativa e non ha alcun effetto in quanto gcc non ottimizza il codice all'interno di un'istruzione asm di base. AssemblerInstructions può contenere più istruzioni di assemblaggio. Un'istruzione asm di base viene utilizzata se si dispone di una routine asm che deve esistere al di fuori di una funzione C. Il seguente esempio è tratto dal manuale GCC:

 /* Note that this code will not compile with -masm=intel */
 #define DebugBreak() asm("int $3")

In questo esempio, è possibile utilizzare DebugBreak() in altri punti del codice e verrà eseguita l'istruzione di assemblaggio int $3 . Nota che anche se gcc non modificherà alcun codice in un'istruzione asm di base, l'ottimizzatore potrebbe comunque spostare istruzioni asm consecutive attorno. Se si dispone di più istruzioni di assemblaggio che devono essere eseguite in un ordine specifico, includerle in una dichiarazione asm.

gcc Supporto esteso asm

Il supporto esteso di asm in gcc ha la seguente sintassi:

asm [volatile] ( AssemblerTemplate
                  : OutputOperands
                  [ : InputOperands
                  [ : Clobbers ] ])
 
 asm [volatile] goto ( AssemblerTemplate
                       :
                       : InputOperands
                       : Clobbers
                       : GotoLabels)

dove AssemblerTemplate è il modello per l'istruzione assembler, OutputOperands sono tutte le variabili C che possono essere modificate dal codice assembly, InputOperands sono tutte le variabili C utilizzate come parametri di input, Clobbers sono un elenco o registri modificati dal codice assembly e GotoLabels sono tutte le etichette di istruzioni goto che possono essere utilizzate nel codice assembly.

Il formato esteso viene utilizzato all'interno delle funzioni C ed è l'utilizzo più tipico dell'assembly inline. Di seguito è riportato un esempio del kernel di Linux per lo scambio di byte a 16 bit e numeri a 32 bit per un processore ARM:

/* From arch/arm/include/asm/swab.h in Linux kernel version 4.6.4 */
#if __LINUX_ARM_ARCH__ >= 6

static inline __attribute_const__ __u32 __arch_swahb32(__u32 x)
{
    __asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
    return x;
}
#define __arch_swahb32 __arch_swahb32
#define __arch_swab16(x) ((__u16)__arch_swahb32(x))

static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
{
    __asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
    return x;
}
#define __arch_swab32 __arch_swab32

#endif

Ogni sezione di asm usa la variabile x come parametro di input e output. La funzione C restituisce quindi il risultato manipolato.

Con il formato asm esteso, gcc può ottimizzare le istruzioni di assemblaggio in un blocco asm seguendo le stesse regole che usa per l'ottimizzazione del codice C. Se vuoi che la tua sezione asm non venga toccata, usa la parola chiave volatile per la sezione asm.

gcc Assieme in linea in macro

Possiamo inserire istruzioni di assemblaggio all'interno di una macro e utilizzare la macro come se fosse chiamata una funzione.

#define mov(x,y) \
{ \
    __asm__ ("l.cmov %0,%1,%2" : "=r" (x) : "r" (y), "r" (0x0000000F)); \
}

/// some definition and assignment
unsigned char sbox[size][size];
unsigned char sbox[size][size];

///Using
mov(state[0][1], sbox[si][sj]);

L'uso di istruzioni di assemblaggio inline incorporate nel codice C può migliorare il tempo di esecuzione di un programma. Questo è molto utile in situazioni di tempo critico come algoritmi crittografici come AES. Ad esempio, per una semplice operazione di spostamento che è necessaria nell'algoritmo AES, possiamo sostituire un'istruzione di montaggio Rotate Right diretta con l'operatore C shift >> .

In un'implementazione di 'AES256', nella funzione 'AddRoundKey ()' abbiamo alcune istruzioni come questa:

unsigned int w;          // 32-bit
unsigned char subkey[4]; // 8-bit, 4*8 = 32 

subkey[0] = w >> 24;     // hold 8 bit, MSB, leftmost group of 8-bits 
subkey[1] = w >> 16;     // hold 8 bit, second group of 8-bit from left    
subkey[2] = w >> 8;      // hold 8 bit, second group of 8-bit from right
subkey[3] = w;           // hold 8 bit, LSB, rightmost group of 8-bits

/// subkey <- w

Assegnano semplicemente il valore di bit di w all'array di subkey .

Possiamo cambiare tre turni + assegnare e assegnare un'espressione C con un solo assieme Rotate Right .

__asm__ ("l.ror  %0,%1,%2" : "=r" (* (unsigned int *) subkey)  : "r" (w), "r" (0x10));

Il risultato finale è esattamente lo stesso.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow