online emulator disassembler compiler assembler asm and assembly x86 disassembly machine-instruction

assembly - emulator - ¿Por qué las instrucciones de ensamblaje pueden contener multiplicaciones en la instrucción "lea"?



mov assembly (3)

Estoy trabajando en una parte de la aplicación de muy bajo nivel en la que el rendimiento es crítico.

Mientras investigaba el ensamblaje generado, noté las siguientes instrucciones:

lea eax,[edx*8+8]

Estoy acostumbrado a ver adiciones al usar referencias de memoria (por ejemplo, [edx + 4]), pero esta es la primera vez que veo una multiplicación.

  • ¿Esto significa que el procesador x86 puede realizar multiplicaciones simples en la instrucción lea?
  • ¿Esta multiplicación tiene un impacto en la cantidad de ciclos necesarios para ejecutar la instrucción?
  • ¿La multiplicación está limitada a potencias de 2 (supongo que este es el caso)?

Gracias por adelantado.


Para ampliar mi comentario y responder el resto de la pregunta ...

Sí, está limitado a poderes de dos. (2, 4 y 8 específicamente) Por lo tanto, no se necesita un multiplicador ya que es solo un cambio. El objetivo es generar rápidamente una dirección a partir de una variable de índice y un puntero, donde el tipo de datos es una palabra simple de 2, 4 u 8 bytes. (Aunque a menudo también se usa para otros usos).

En cuanto a la cantidad de ciclos necesarios: según las tablas de Agner Fog, parece que la instrucción lea es constante en algunas máquinas y variable en otras.

En Sandy Bridge hay una penalización de 2 ciclos si es "complejo o irregular". Pero no dice qué significa "complejo" ... Así que solo podemos adivinar a menos que haga un punto de referencia.


Para ampliar tu última pregunta:

¿La multiplicación está limitada a potencias de 2 (supongo que este es el caso)?

Tenga en cuenta que obtiene el resultado del base + scale * index , por lo que si la scale debe ser 1, 2, 4 u 8 (el tamaño de los tipos de datos enteros x86), puede obtener el equivalente de una multiplicación mediante algunas constantes diferentes utilizando el mismo registro como base e index , por ejemplo:

lea eax, [eax*4 + eax] ; multiply by 5

Esto es utilizado por el compilador para hacer la reducción de la fuerza, por ejemplo: para una multiplicación por 100, dependiendo de las opciones del compilador (modelo de CPU objetivo, opciones de optimización), puede obtener:

lea (%edx,%edx,4),%eax ; eax = orig_edx * 5 lea (%eax,%eax,4),%eax ; eax = eax * 5 = orig_edx * 25 shl $0x2,%eax ; eax = eax * 4 = orig_edx * 100


En realidad, esto no es algo específico de la instrucción lea .

Este tipo de direccionamiento se denomina Scaled Addressing Mode . La multiplicación se logra mediante un cambio de bit, que es trivial:

También podría hacer ''direccionamiento a escala'' con un mov , por ejemplo (tenga en cuenta que esta no es la misma operación, la única similitud es el hecho de que ebx*4 representa una multiplicación de direcciones):

mov edx, [esi+4*ebx]

(fuente: http://www.cs.virginia.edu/~evans/cs216/guides/x86.html#memory )

Para obtener una lista más completa, consulte este documento de Intel . La Tabla 2-3 muestra que se permite una escala de 2, 4 u 8. Nada más.

Latencia (en términos de número de ciclos): no creo que esto se vea afectado en absoluto. Un cambio es una cuestión de conexiones, y la selección entre tres posibles cambios es la cuestión del retraso de 1 multiplexor.