2017-09-27 15 views
0

J'ai essayé de comprendre comment faire une copie de mémoire via un tampon.Copie d'ESI vers Buffer vers EDI

Les paramètres de ma fonction sont: void* dest, void* src, size_t length

-je configurer ma fonction comme ceci:

push ebp 
mov ebp, esp 
push edi 
push esi 
push ebx 

mov edi, [ebp+0x8] ; this is dest 
mov esi, [ebp+0xc] ; this is src 
mov ecx, [ebp+0x10] ; this is length 

Je suis un peu d'une perte sur ce qu'il faut faire ensuite. Je comprends que j'ai besoin de créer un tampon parce que je pourrais potentiellement avoir de la mémoire qui se chevauche, mais je ne sais pas comment définir ma mémoire tampon dans ma fonction.

Une fois que je fais, j'imagine le code suivant ressemblerait à quelque chose comme (en supposant ebx comme le tampon):

mov ebx, [esi+4*ecx] 
mov edi, [ebx] 

pop edi 
pop esi 
pop ebx 
mov esp, ebp 
pop ebp 

Merci à l'avance! Edit: Pour clarifier, je mets un de mes commentaires ici: Essentiellement, je veux prendre les données stockées dans esi et le déplacer à edi, mais je veux aussi éviter la situation où il pourrait y avoir de la mémoire chevaucher esi et edi. Je crois, en utilisant quelque chose comme un tampon pourrait accomplir cela (est-ce que j'utilise le terme incorrectement?).

+0

"La copie de mémoire via un tampon" n'est pas assez précise d'une description pour comprendre ce que vous voulez. Pourriez-vous élaborer? – fuz

+0

Désolé pour le manque de clarté, je suis très nouveau pour l'assemblage. Essentiellement, je veux prendre les données stockées dans 'esi' et les déplacer dans' edi', mais je veux aussi éviter la situation où il pourrait y avoir un chevauchement de mémoire entre 'esi' et' edi'. Je crois, en utilisant quelque chose comme un tampon pourrait accomplir cela (est-ce que j'utilise le terme incorrectement?). –

+2

pour 'memcpy' après votre installation, vous pouvez faire' rep movsb' pour copier le bloc de mémoire. Mais pour les régions chevauchantes 'memcpy' est UB, alors' memmove' devrait être utilisé. Ce qui permet de détecter dans quelle direction se produit le chevauchement et de le copier depuis le début ou la fin du bloc.Dans un assemblage simple et naïf, vous pouvez utiliser 'rep movsb' à nouveau, mais avec' std' (drapeau de direction défini sur 1). Juste ajouter à la valeur de pointeurs (taille-1). Cela dit une telle routine n'aura pas la meilleure performance possible, qui aurait besoin de code optimisé pour les différentes familles de processeurs x86, la résolution de l'alignement, etc. Donc, vérifiez quelques didacticiels/docs 'rep movsb'? – Ped7g

Répondre

2

Il y a deux choses ici. Tout d'abord, la mémoire se chevauchant est généralement traitée en changeant la direction dans laquelle la copie est effectuée. Vous devriez d'abord vous convaincre que peu importe la façon dont les deux régions se chevauchent, soit en commençant à l'adresse la plus basse de chaque bloc et en copiant de la source à la destination, en incrémentant les pointeurs pour chaque octet; ou en commençant à l'adresse la plus élevée dans chaque bloc et en copiant de la même manière, mais ensuite en décrémentant les pointeurs fonctionnera. L'utilisation d'un tampon intermédiaire nécessite soit de paver la copie contre un tampon de taille fixe, ce qui nécessite encore de manipuler la direction, ou d'appeler, par ex. malloc, qui est la plupart du temps juste lent, mais nécessite également de comprendre comment appeler une fonction de l'assemblage. Pour commencer, je suggère d'écrire la direction conditionnelle et deux boucles en C/C++ ou similaire. (Une langue avec des pointeurs aide.) I.e. écrivez votre propre copie de memmove dans C.

À ce stade, vous devez traduire une instruction if, une boucle et une copie de la source vers la destination, en assembly. Tout cela est assez simple et il y a quelques suggestions dans les commentaires sur la façon d'utiliser les instructions x86 pour faire une boucle comptée pour vous. (Notez que si vous utilisez le support intégré, vous devez connaître l'indicateur de direction x86, par exemple les instructions CLD et STD Je commencerais par le faire à main levée, puis passer au support REP *.)

Une façon d'obtenir un bon traitement est d'écrire du code C/C++ et d'utiliser l'indicateur de sortie de l'assembly pour le compilateur (par exemple -S sur la plupart des systèmes UNIXy).

+0

Merci pour votre publication! Je jetais un oeil à un simple memmove que j'ai implémenté en C++ qui a commencé par copier une chaîne à partir du dernier élément en premier. 'pour (int i = n; i> 0; i ++) dest [i] = src [i];'. J'ai fait une simple boucle dans l'assemblage 'cmp ecx, 0',' je bas ', 'mov eax, dword ptr [dest]', 'ajouter eax, dword ptr [ebp-8]', 'dec ecx',' jmp top'. Ça ne fonctionne pas encore pour moi. –

+1

Les chaînes impliquent généralement des tests pour l'octet nul, ce qui est bien, mais tend à faire les compromis un peu différent d'une copie comptée. Il est peut-être surprenant que quelque chose d'aussi simple que memcpy/memmove puisse entraîner autant de compromis dans la mise en œuvre, mais cela tend à être la nature de l'optimisation des performances à ce niveau. Si vous savez que vous copiez de grands tampons alignés et que vous disposez du jeu d'instructions complet, il est probablement utile d'utiliser les registres SIMD, mais normalement memmove ne peut pas le faire. –