Výuka assembleru
9. Instrukce pro práci s bloky paměti
Velmi užitečnou skupinou instrukcí procesorů řady X86 jsou instrukce pro práci s bloky. Do této skupiny instrukcí patří instrukce pro kopírování, plnění, porovnávání a prohledávání celých bloků dat.
Jako úvod k dnešnímu tématu napíšeme funkci, která bude kopírovat blok paměti. Funkce bude přijímat tři parametry: adresa zdrojového bloku paměti, adresa cílového bloku paměti a počet bytů, který má být zkopírován. V assembleru tuto funkci napíšeme asi takto:
CopyMemoryBlock PROC C pSrc:PTR, pDest:PTR, nBytes:DWORD push esi push edi ; Pro jistotu uložíme ESI a EDI mov esi, pSrc mov edi, pDest mov ecx, nBytes; ; ECX obsahuje počet bytů __CopyByte: jcxz __EndCopy mov al, [esi] ; Načteme jeden byte inc esi mov [edi], al inc edi dec ecx jmp __CopyByte __EndCopy: pop edi pop esi ret CopyMemoryBlock ENDP
Funkce se dá zjednodušit, pokud použijeme některé z instrukcí uvedených v tabulce:
Instrukce | Nahrazuje | Poznámka |
---|---|---|
lodsb | mov al, [esi] inc esi |
|
lodsw | mov ax, [esi] add esi, 2 |
|
lodsd | mov eax, [esi] add esi, 4 |
|
stosb | mov [edi], al inc edi |
|
stosw | mov [edi], ax add edi, 2 |
|
stosd | mov [edi], eax add edi, 4 |
|
movsb | mov byte ptr [edi], byte ptr [esi]* inc esi inc edi |
*) instrukce "mov byte ptr [edi], byte ptr [esi]" neexistuje Instrukce nemění hodnotu žádného jiného registru kromě ESI a EDI. |
movsw | mov word ptr [edi], word ptr [esi]* add esi, 2 add edi, 2 |
*) instrukce "mov word ptr [edi], word ptr [esi]" neexistuje Instrukce nemění hodnotu žádného jiného registru kromě ESI a EDI. |
movsd | mov dword ptr [edi], dword ptr [esi]* add esi, 4 add edi, 4 |
*) instrukce "mov dword ptr [edi], dword ptr [esi]" neexistuje Instrukce nemění hodnotu žádného jiného registru kromě ESI a EDI. |
Vidíme, že naši posloupnost instrukcí pro kopírování bytu z adresy [esi] na adresu [edi] se dá nahradit buďto dvojicí instrukcí lodsb a stosb, nebo jedinou instrukcí movsb. Počet instrukcí se tak o něco zmenší, program bude i rychlejší:
__CopyByte: jcxz __EndCopy movsb dec ecx jmp __CopyByte __EndCopy: ...
Instrukce lodsX, stosX a movsX mají ještě jednu vlastnost, která z nich dělá instrukce pro kopírování celých bloků paměti. Touto vlastností je instrukční prefix rep (repeat), který způsobí opakování instrukce. Počet opakování instrukce je uložen v registru ECX. Použitím prefixu rep před instrukcí movsb umožňuje podstatně zkrátit celou funkci CopyMemoryBlock:
CopyMemoryBlock PROC C pSrc:PTR, pDest:PTR, nBytes:DWORD push esi push edi ; Pro jistotu uložíme ESI a EDI mov esi, pSrc mov edi, pDest mov ecx, nBytes; ; ECX obsahuje počet bytů rep movsb pop edi pop esi ret CopyMemoryBlock ENDP
Vidíme že, celý cyklus pro kopírování bloku se nám podařilo zmenšit na pouhou jednu instrukci
rep movsb !!!
Pokud budeme sledovat provedení instrukce rep movsb v debuggeru,
zjistíme, že po provedení instrukce bude obsah registru ECX vynulován. To je proto,
že každé opakování instrukce movsb (způsobené prefixem rep) sníží hodnotu registru
ECX o 1. Jakmile je hodnota v registru ECX nula, opakování se přeruší.
Následující tabulka zobrazuje zbývající instrukce pro práci s bloky:
Instrukce | Nahrazuje | Poznámka |
---|---|---|
cmpsb | cmp byte ptr [esi], byte ptr [edi]* inc esi inc edi |
*) instrukce "cmp byte ptr [edi], byte ptr [esi]" neexistuje |
cmpsw | cmp word ptr [esi], word ptr [edi]* add esi, 2 add edi, 2 |
*) instrukce "cmp word ptr [esi], word ptr [edi]" neexistuje |
cmpsd | cmp dword ptr [esi], dword ptr [edi]* add esi, 4 add edi, 4 |
*) instrukce "cmp dword ptr [esi], dword ptr [edi]" neexistuje |
scasb | cmp byte ptr [edi], al inc edi |
Pokud použijeme prefix rep, provede se instrukce buďto do nalezení shody [edi] a al/ax/eax, nebo tolikrát, kolik je uloženo v registru ECX. |
scasw | cmp word ptr [edi], ax add edi, 2 |
|
scasd | cmp dword ptr [edi], eax add edi, 4 |
Instrukce pro kopírování bloků se používají ve funkcích C, jako jsou memcpy, memmove, memset a jiných.
Copyright Ladislav Zezula 2004