Quel est le but de L'instruction LEA?

pour moi, ça ressemble à un funky MOV. Quel est son but et quand dois-je utiliser?

544
demandé sur Michael Petch 2009-11-01 23:57:27

14 réponses

comme d'autres l'ont souligné, LEA (load effective address) est souvent utilisé comme un" truc " pour faire certains calculs, mais ce n'est pas son but principal. L'ensemble d'instruction x86 a été conçu pour prendre en charge des langages de haut niveau comme Pascal et C, où les tableaux-en particulier les tableaux d'ints ou de petites structures-sont communs. Considérons, par exemple, une structure représentant les coordonnées (x, y):

struct Point
{
     int xcoord;
     int ycoord;
};

imaginez maintenant une déclaration comme:

int y = points[i].ycoord;

points[] est un tableau de Point . En supposant que la base du tableau est déjà dans EBX , et la variable i est dans EAX , et xcoord et ycoord sont chacun 32 bits (donc ycoord est à l'offset 4 octets dans la structure), cette déclaration peut être compilée à:

MOV EDX, [EBX + 8*EAX + 4]    ; right side is "effective address"

qui atterrira y dans EDX . Le facteur d'échelle de 8 est parce que chaque Point est de 8 octets. Considérons maintenant la même expression utilisée avec "adresse de" operator&:

int *p = &points[i].ycoord;

Dans ce cas, vous ne voulez pas la valeur de ycoord , mais son adresse. C'est là que LEA (charge efficace de l'adresse). Au lieu d'un MOV , le compilateur peut générer

LEA ESI, [EBX + 8*EAX + 4]

qui chargera l'adresse dans ESI .

667
répondu I. J. Kennedy 2012-12-18 22:11:00

De la "Zen" Assemblage par Abrash:

LEA , la seule instruction qui effectue des calculs d'adressage de mémoire, mais ne s'adresse pas réellement à la mémoire. LEA accepte un opérande d'adressage de mémoire standard, mais ne fait rien de plus que de stocker l'offset de mémoire calculé dans le registre spécifié, qui peut être n'importe quel registre à usage général.

Qu'est-ce que ça nous donne? Deux choses que ADD ne fournit pas:

  1. la capacité d'effectuer l'addition avec deux ou trois opérandes, et
  2. la capacité de stocker le résultat dans n'importe quel Registre; pas seulement un des opérandes source.

Et LEA ne modifie pas les drapeaux.

exemples

  • LEA EAX, [ EAX + EBX + 1234567 ] calcule EAX + EBX + 1234567 (c'est-à-dire trois opérandes)
  • LEA EAX, [ EBX + ECX ] calcule EBX + ECX sans passer par le résultat.
  • multiplication par constante (par deux, trois, cinq ou neuf), si vous l'utilisez comme LEA EAX, [ EBX + N * EBX ] (N peut être 1,2,4,8).

autre usecase est pratique dans les boucles: la différence entre LEA EAX, [ EAX + 1 ] et INC EAX est que ce dernier change EFLAGS mais le premier non; cela préserve l'état CMP .

469
répondu Frank Krueger 2018-04-16 03:09:40

une autre caractéristique importante de l'instruction LEA est qu'elle ne modifie pas les codes de condition tels que CF et ZF , alors que le calcul de l'adresse par des instructions arithmétiques comme ADD ou MUL le fait. Cette fonctionnalité diminue le niveau de dépendance entre les instructions et permet ainsi une optimisation supplémentaire par le compilateur ou l'ordonnanceur matériel.

87
répondu Angus Lee 2018-04-16 02:51:14

malgré toutes les explications, LEA est une opération arithmétique:

LEA Rt, [Rs1+a*Rs2+b] =>  Rt = Rs1 + a*Rs2 + b

c'est juste que son nom est extrêmement stupide pour une opération shift+add. La raison en a déjà été expliquée dans les réponses les mieux cotées (c.-à-d. qu'elle a été conçue pour cartographier directement les références de mémoire de haut niveau).

72
répondu hdante 2018-04-16 02:47:01

peut-être juste une autre chose à propos de Lea instruction. Vous pouvez également utiliser LEA pour la multiplication rapide des registres par 3, 5 ou 9.

LEA EAX, [EAX * 2 + EAX]   ;EAX = EAX * 3
LEA EAX, [EAX * 4 + EAX]   ;EAX = EAX * 5
LEA EAX, [EAX * 8 + EAX]   ;EAX = EAX * 9
65
répondu GJ. 2015-01-15 19:42:48

lea est une abréviation de "load effective address". Il charge l'adresse de la référence de localisation par l'opérande source vers l'opérande de destination. Par exemple, vous pouvez l'utiliser pour:

lea ebx, [ebx+eax*8]

déplacer ebx pointeur eax éléments supplémentaires (en 64 bits/élément de tableau) avec une seule instruction. Fondamentalement, vous bénéficiez de modes d'adressage complexes supportés par l'architecture x86 pour manipuler efficacement les pointeurs.

51
répondu Mehrdad Afshari 2009-11-01 21:00:24

La principale raison pour laquelle vous utilisez LEA plus d'un MOV est si vous devez effectuer une opération arithmétique sur les registres que vous utilisez pour calculer l'adresse. En effet, vous pouvez effectuer ce qui se résume à pointer arithmétique sur plusieurs des registres en combinaison efficacement pour "gratuit."

ce qui est vraiment déroutant à ce sujet est que vous écrivez typiquement un LEA comme un MOV mais vous n'êtes pas réellement déréférencement de la mémoire. En d'autres termes:

MOV EAX, [ESP+4]

cela déplacera le contenu de ce que ESP+4 pointe dans EAX .

LEA EAX, [EBX*8]

cela déplacera l'adresse effective EBX * 8 dans EAX, pas ce qui est trouvé dans cet endroit. Comme vous pouvez le voir, aussi, il est possible de multiplier par des facteurs de deux (échelle) alors qu'un MOV est limité à ajouter/soustraire.

19
répondu David Hoelzer 2015-05-05 22:22:04

le 8086 a une grande famille d'instructions qui acceptent un opérande de registre et une adresse effective, effectuent quelques calculs pour calculer la partie offset de cette adresse effective, et effectuent une certaine opération impliquant le registre et la mémoire mentionnée par l'adresse calculée. Il était assez simple d'avoir une des instructions dans cette famille se comporter comme ci-dessus, sauf pour sauter cette opération mémoire réelle. Ceci, les instructions:

mov ax,[bx+si+5]
lea ax,[bx+si+5]

ont été mis en œuvre de façon presque identique à l'interne. La différence est une étape sautée. Les deux instructions fonctionnent quelque chose comme:

temp = fetched immediate operand (5)
temp += bx
temp += si
address_out = temp  (skipped for LEA)
trigger 16-bit read  (skipped for LEA)
temp = data_in  (skipped for LEA)
ax = temp

quant à savoir pourquoi Intel pensait que cette instruction en valait la peine, Je ne suis pas vraiment sûr, mais le fait qu'elle soit peu coûteuse à mettre en œuvre aurait été un facteur important. Un autre facteur aurait été le fait que L'assembleur Intel permettait de définir des symboles par rapport au registre BP. Si fnord a été défini comme un BP-symbole relatif (par exemple BP+8), on pourrait dire:

mov ax,fnord  ; Equivalent to "mov ax,[BP+8]"

si l'on voulait utiliser quelque chose comme stosw pour stocker des données à une adresse relative BP, être en mesure de dire

mov ax,0 ; Data to store
mov cx,16 ; Number of words
lea di,fnord
rep movs fnord  ; Address is ignored EXCEPT to note that it's an SS-relative word ptr

était plus commode que:

mov ax,0 ; Data to store
mov cx,16 ; Number of words
mov di,bp
add di,offset fnord (i.e. 8)
rep movs fnord  ; Address is ignored EXCEPT to note that it's an SS-relative word ptr

noter qu'oublier le monde "offset" ferait en sorte que le contenu de l'emplacement [BP+8], plutôt que la valeur 8, soit ajouté à DI. Oops.

16
répondu supercat 2018-04-16 02:48:33

comme les réponses existantes l'ont mentionné, LEA a les avantages d'effectuer l'arithmétique d'adressage de mémoire sans accéder à la mémoire, enregistrant le résultat arithmétique à un registre différent au lieu de la forme simple de l'instruction d'ajout. Le véritable avantage de performance sous-jacent est que le processeur moderne dispose d'une unité et d'un port LEA ALU séparés pour la génération d'adresse efficace (y compris LEA et autre adresse de référence de mémoire), ce qui signifie l'opération arithmétique en LEA et d'autres opérations arithmétiques normales dans L'ALU pourraient être effectuées en parallèle dans un noyau.

voir cet article de Haswell architecture pour plus de détails sur l'unité LEA: http://www.realworldtech.com/haswell-cpu/4 /

un autre point important qui n'est pas mentionné dans d'autres réponses est l'instruction LEA REG, [MemoryAddress] PIC (code indépendant de la position) qui Code L'adresse relative du PC dans cette instruction à la référence MemoryAddress . Ceci est différent de MOV REG, MemoryAddress qui Code l'adresse virtuelle relative et nécessite le déplacement/correction dans les systèmes d'exploitation modernes (comme ASLR est caractéristique commune). Ainsi LEA peut être utilisé pour convertir un tel non PIC en PIC.

10
répondu Thomson 2015-10-10 03:31:06

l'instruction LEA peut être utilisée pour éviter les calculs chronophages des adresses effectives par le CPU. Si une adresse est utilisée de façon répétée, il est plus efficace de la stocker dans un registre au lieu de calculer l'adresse effective chaque fois qu'elle est utilisée.

7
répondu red-E 2013-06-04 20:32:59

voici un exemple.

// compute parity of permutation from lexicographic index
int parity (int p)
{
  assert (p >= 0);
  int r = p, k = 1, d = 2;
  while (p >= k) {
    p /= d;
    d += (k << 2) + 6; // only one lea instruction
    k += 2;
    r ^= p;
  }
  return r & 1;
}

avec l'option-O (optimize) comme compilateur, gcc trouvera l'instruction lea pour la ligne de code indiquée.

6
répondu user3634373 2014-05-16 19:40:55

l'instruction LEA (Load Effective Address) permet d'obtenir l'adresse qui provient de l'un des modes d'adressage mémoire du processeur Intel.

, C'est-à-dire, si nous avons un déplacement des données comme ceci:

MOV EAX, <MEM-OPERAND>

il déplace le contenu de l'emplacement mémoire désigné dans le registre cible.

si nous remplaçons le MOV par LEA , alors l'adresse de l'emplacement de la mémoire est calculé exactement de la même façon par l'expression d'adressage <MEM-OPERAND> . Mais au lieu de le contenu de l'emplacement mémoire, nous obtenons l'emplacement lui-même dans la destination.

LEA n'est pas une instruction arithmétique spécifique; c'est un moyen d'intercepter l'adresse effective provenant de l'un des modes d'adressage mémoire du processeur.

par exemple, nous pouvons utiliser LEA sur une simple adresse directe. Aucune arithmétique n'est impliqué du tout:

MOV EAX, GLOBALVAR   ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR   ; fetch the address of GLOBALVAR into EAX.

ceci est valide; nous pouvons le tester à L'invite Linux:

$ as
LEA 0, %eax
$ objdump -d a.out

a.out:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
   0:   8d 04 25 00 00 00 00    lea    0x0,%eax

ici, il n'y a pas d'addition d'une valeur d'échelle, ni d'offset. Zéro est déplacé dans EAX. Nous pourrions le faire en utilisant MOV avec une opérande immédiate aussi.

C'est la raison pour laquelle les gens qui pensent que les crochets dans LEA sont superflus se trompent gravement; les crochets ne sont pas LEA syntaxe mais sont une partie de la mode d'adressage.

LEA est réel au niveau matériel. L'instruction générée code le mode d'adressage réel et le processeur l'exécute au point de calculer l'adresse. Puis il déplace cette adresse vers la destination au lieu de générer une référence de mémoire. (Puisque le calcul d'adresse d'un mode d'adressage dans toute autre instruction n'a aucun effet sur les pavillons CPU, LEA n'a aucun effet sur les pavillons CPU.)

Contraste avec le chargement de la valeur de l'adresse zéro:

$ as
movl 0, %eax
$ objdump -d a.out | grep mov
   0:   8b 04 25 00 00 00 00    mov    0x0,%eax

c'est un encodage très similaire, vous voyez? Juste le 8d de LEA a changé en 8b .

bien sûr, ce codage LEA est plus long que le déplacement d'un zéro immédiat dans EAX :

$ as
movl "151940920", %eax
$ objdump -d a.out | grep mov
   0:   b8 00 00 00 00          mov    "151940920"x0,%eax

il n'y a pas de raison pour LEA d'exclure cette possibilité bien que juste parce qu'il y a une alternative plus courte; il est combinaison orthogonale avec les modes d'adressage disponibles.

6
répondu Kaz 2018-03-28 21:09:00

LEA: juste une instruction "arithmétique"..

MOV transfère des données entre opérandes mais lea ne fait que calculer

4
répondu the accountant 2015-05-05 21:06:00

il parce qu'à la place vous écrivez le code

mov dx,offset something

vous pouvez simplement écrire

lea dx,something
-6
répondu user2988239 2013-12-22 19:50:25