Domanda

Sto cercando di imparare l'assembly (quindi abbi pazienza) e ricevo un errore di compilazione su questa riga:

mov byte [t_last], [t_cur]

L'errore è

error: invalid combination of opcode and operands

Sospetto che la causa di questo errore sia semplicemente che non è possibile per un'istruzione mov spostarsi tra due indirizzi di memoria, ma mezz'ora di ricerca su Google e non sono stato in grado di confermarlo: è così?

Inoltre, supponendo che io abbia ragione, ciò significa che devo utilizzare un registro come punto intermedio per copiare la memoria:

mov cl, [t_cur]
mov [t_last], cl

Qual è il registro consigliato da utilizzare (o dovrei invece utilizzare lo stack)?

È stato utile?

Soluzione

Il sospetto è corretto, non è possibile spostare dalla memoria alla memoria.

Ogni registro di uso generale farà. Ricordate di spingere il registro se non siete sicuri di ciò che è al suo interno e per ripristinare indietro una volta fatto.

Altri suggerimenti

E 'davvero semplice in 16 bit, basta fare il seguente:

     push     di
     push     si
     push     cx
     mov      cx,(number of bytes to move)
     lea      di,(destination address)
     lea      si,(source address)
     rep      movsb
     pop      cx
     pop      si
     pop      di

Nota: le spinte e pop sono neceessary se è necessario salvare il contenuto dei registri

.

C'è anche un comando MOVS di muoversi dati dalla memoria alla memoria:

MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS

È tecnicamente possibile passare dalla memoria alla memoria.

Provare a utilizzare MOVS (stringa movimento), e l'impostazione [E] SI e [E] DI , a seconda che si desidera trasferire byte (s), parola (s), ecc.

mov si, t_cur    ; Load SI with address of 't_cur'
mov di, t_last   ; Load DI with address of 't_last'
movsb            ; Move byte from [SI] to [DI]

; Some dummy data
t_cur    db 0x9a ; DB tells NASM that we want to declare a byte
t_last   db 0x7f ; (See above)

Questo è meno efficiente rispetto all'utilizzo di un carico normale + negozio con un registro temporaneo, ma lo fa fare la copia reale con una sola istruzione.

Ecco come MOVS dovrebbe essere utilizzato, e come funziona: https://www.felixcloutier.com/x86/movs:movsb: movsw: movsd: movsq

E 'normalmente utilizzato solo con un prefisso rep per le copie di blocco, non per un singolo elemento. (CPU moderni hanno microcodice abbastanza efficiente per rep movsb che vicino alla velocità di un ciclo usando AVX vettore istruzioni load / store.)

Esatto, il codice macchina x86 non può codificare un'istruzione con due esplicito operandi di memoria (indirizzi arbitrari specificati in [])

Qual è il registro consigliato?

Qualsiasi registro che non è necessario salvare/ripristinare.

In tutte le principali convenzioni di chiamata a 32 e 64 bit, EAX, ECX ed EDX vengono bloccati nelle chiamate, quindi AL, CL e DL sono buone scelte.Per una copia in byte o word, in genere si desidera un file movzx caricare in un registro a 32 bit, quindi in un archivio a 8 o 16 bit.Ciò evita una falsa dipendenza dal vecchio valore del registro.Utilizzare solo un formato stretto a 16 o 8 bit mov caricare se attivamente Volere per fondersi nei bit bassi di un altro valore.x86 movzx è l'analogo di istruzioni come ARM ldrb.

    movzx   ecx,  byte [rdi]       ; load CL, zero-extending into RCX
    mov    [rdi+10], cl

Nella modalità a 64 bit, anche SIL, DIL, r8b, r9b e così via sono ottime scelte, ma richiedono un prefisso REX nel codice macchina per il negozio, quindi c'è un motivo minore di dimensione del codice per evitarli.

In genere evita di scrivere AH, BH, CH o DH per motivi di prestazioni, a meno che tu non abbia letto e compreso i seguenti collegamenti e qualsiasi falsa dipendenza o stallo di fusione di registri parziali non sarà un problema o non si verificherà affatto nel tuo codice .


(o dovrei invece usare lo stack)?

Prima di tutto, non puoi inviare un singolo byte, quindi non è possibile eseguire un caricamento/memorizzazione di byte dallo stack.Per una parola, dword o qword (a seconda della modalità della CPU), potresti push [src] / pop [dst], ma è molto più lento della copia tramite un registro.Introduce una latenza aggiuntiva di archiviazione/ricaricamento dell'inoltro dello store prima che i dati possano essere letti dalla destinazione finale e richiede più uops.

A meno che non si trovi da qualche parte nello stack È la destinazione desiderata e non è possibile ottimizzare la variabile locale in un registro, nel qual caso push [src] va bene copiarlo lì e allocare spazio nello stack per esso.

Vedere https://agner.org/optimize/ e altri collegamenti alle prestazioni x86 il wiki dei tag x86

Voglio solo per discutere di "barriera di memoria" con voi. Nel codice C

a = b;//Take data from b and puts it in a

sarebbe assemblato a

mov %eax, b # suppose %eax is used as the temp
mov a, %eax

Il sistema non può garantire l'atomicità della cessione. Ecco perché abbiamo bisogno di un rmb (Barriera di lettura)

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