Intel x86 Assembly Language & Microarchitecture
Mejoramiento
Buscar..
Introducción
Observaciones
En caso de duda, siempre puede consultar el Manual de referencia de optimización de arquitecturas Intel 64 y IA-32 , que es un gran recurso de la compañía detrás de la arquitectura x86.
Poner a cero un registro
La forma obvia de poner a cero un registro es MOV en un 0 ejemplo:
B8 00 00 00 00 MOV eax, 0
Tenga en cuenta que esta es una instrucción de 5 bytes.
Si está dispuesto a pegar las banderas ( MOV nunca afecta a las banderas), puede usar la instrucción XOR para hacer bitwise-XOR el registro consigo mismo:
33 C0 XOR eax, eax
Esta instrucción requiere solo 2 bytes y se ejecuta más rápido en todos los procesadores .
Mover la bandera de Carry a un registro
Fondo
Si el indicador de Carry ( C ) tiene un valor que desea poner en un registro, la forma más ingenua es hacer algo como esto:
mov al, 1
jc NotZero
mov al, 0
NotZero:
Utilice 'sbb'
Una forma más directa, evitando el salto, es usar "Restar con préstamo":
sbb al,al ; Move Carry to al
Si C es cero, entonces al será cero. De lo contrario será 0xFF ( -1 ). Si necesita que sea 0x01 , agregue:
and al, 0x01 ; Mask down to 1 or 0
Pros
- Sobre el mismo tamaño
- Dos o una instrucciones menos.
- Ningún salto caro
Contras
- Es opaco para un lector que no está familiarizado con la técnica.
- Altera otras banderas.
Prueba un registro para 0
Fondo
Para averiguar si un registro contiene un cero, la técnica ingenua es hacer esto:
cmp eax, 0
Pero si miras el código de operación para esto, obtienes esto:
83 F8 00 cmp eax, 0
test uso
test eax, eax ; Equal to zero?
Examine el código de operación que obtiene:
85 c0 test eax, eax
Pros
- Sólo dos bytes!
Contras
- Opaco a un lector no familiarizado con la técnica.
También puede consultar la pregunta de preguntas y respuestas sobre esta técnica .
Sistema Linux llama con menos hinchazón
En Linux de 32 bits, las llamadas al sistema generalmente se realizan mediante la instrucción sysenter (yo digo que generalmente porque los programas más antiguos usan el int 0x80 ahora en desuso), sin embargo, esto puede ocupar mucho espacio en un programa, por lo que hay formas Puede cortar esquinas para acortar y acelerar las cosas.
Este suele ser el diseño de una llamada al sistema en Linux de 32 bits:
mov eax, <System call number>
mov ebx, <Argument 1> ;If applicable
mov ecx, <Argument 2> ;If applicable
mov edx, <Argument 3> ;If applicable
push <label to jump to after the syscall>
push ecx
push edx
push ebp
mov ebp, esp
sysenter
¡Eso es masivo! Pero hay algunos trucos que podemos tirar para evitar este lío.
El primero es establecer ebp al valor de esp disminuido por el tamaño de 3 registros de 32 bits, es decir, 12 bytes. Esto es genial siempre y cuando esté de acuerdo con sobrescribir ebp, edx y ecx con basura (como cuando moverá un valor a esos registros directamente después de todos modos), podemos hacerlo usando la instrucción LEA para que no sea necesario. Para afectar el valor de ESP en sí.
mov eax, <System call number>
mov ebx, <Argument 1>
mov ecx, <Argument 2>
mov edx, <Argument 3>
push <label to jump to after the syscall>
lea ebp, [esp-12]
sysenter
Sin embargo, no hemos terminado, si la llamada al sistema es sys_exit, podemos evitar que no pongamos nada en absoluto en la pila.
mov eax, 1
xor ebx, ebx ;Set the exit status to 0
mov ebp, esp
sysenter
Multiplica por 3 o 5
Fondo
Para obtener el producto de un registro y una constante y almacenarlo en otro registro, la forma ingenua es hacer esto:
imul ecx, 3 ; Set ecx to 5 times its previous value
imul edx, eax, 5 ; Store 5 times the contend of eax in edx
Usar lea
Las multiplicaciones son operaciones caras. Es más rápido usar una combinación de turnos y adiciones. Para el caso particular de muliplying el contendiente de un registro de 32 o 64 bits que no es esp o rsp por 3 o 5, puede usar la instrucción lea. Esto utiliza el circuito de cálculo de dirección para calcular el producto rápidamente.
lea ecx, [2*ecx+ecx] ; Load 2*ecx+ecx = 3*ecx into ecx
lea edx, [4*edx+edx] ; Load 4*edx+edx = 5*edx into edx
Muchos ensambladores también entenderán
lea ecx, [3*ecx]
lea edx, [5*edx]
Para todos los multiplicandos posibles, otros ebp o rbp , la ebp instrucción resultante es la misma que con el uso de imul .
Pros
- Ejecuta mucho más rápido
Contras
- Si su multiplicando es
ebporbp, toma un byte más usandoimul - Más para escribir si su ensamblador no admite los accesos directos
- Opaco a un lector no familiarizado con la técnica.