Arquitectura x86 de 32 bits Arquitectura de conjunto de instrucciones Intel IA32 Conjunto de instrucciones x86-64 Sistemas Computacionales Mario Medina C. [email protected] Limitaciones de arquitectura de 32 bits Arquitecturas de 64 bits DEC Alpha de 64 bits (1992) Sun SPARC de 64 bits (1995) Intel Itanium (2001) Desarrollada en conjunto con HP 10M transistores Usa VLIW (Very Long Instruction Word) No es compatible con código IA32 existente No tiene el desempeño esperado Conocida como Intel x86 de 32 bits Extiende arquitectura de 16 bits del 8086 Introducida en 1985 con Intel 80386 Espacio de direcciones virtual de 4 GiB Tamaño máximo de archivo de 4 GiB Arquitectura AMD x86-64 AMD se adelanta a Intel en sacar una arquitectura de 64 bits compatible con x86 Arquitectura de difícil implementación El doble de IA32 en 2001 AMD y x86-64 AMD introduce microprocesador de 64 bits extendiendo x86 a 64 bits AMD recluta diseñadores de DEC y otras compañías Arquitectura AMD x86-64 Compatible con Intel x86 de 32 bits Nuevos formatos de datos Mayor capacidad y desempeño Microarquitectura AMD K8 (2003) Líneas Opteron y Athlon 64 lideran el mercado Intel y 64 bits En 2004, Intel introduce Itanium 2 En 2006, Intel introduce Itanium 2 dual-core 1700M transistores! No tiene buenos compiladores No es compatible con código x86 existente Pentium 4 lo supera en razón desempeño/costo En 2004, Intel integra arquitectura EMT64 ©2014 Mario Medina C. 221M transistores Mejora bastante el desempeño Casi idéntico a AMD x86-64 1 Arquitectura AMD x86-64 Punteros de 64 bits Enteros long int de 64 bits Operaciones enteras de 8, 16, 32 y 64 bits 16 registros de propósito general Paso de argumentos via registros en vez de pila Operaciones condicionales Nuevas instrucciones para operaciones de punto flotante Tipos de datos x86-64 Sufijos y largos char (b): 1 byte short (w): 2 bytes int (l): 4 bytes unsigned int (l): 4 bytes long int (q): 8 bytes unsigned long (q): 8 bytes char * (q): 8 bytes float (s): 4 bytes double (d): 8 bytes long double (s): 16 bytes Tipos de datos x86-64 Punteros de 8 bytes (64 bits) permiten direccionar 264 bytes (16 exabytes) de memoria Procesadores Intel y AMD actuales sólo direccionan 248 (256 terabytes) de RAM física Datos long double usan 16 bytes para almacenar números de punto flotante en formato de 80 bits ya visto Sólo son usados 10 bytes menos significativos Registros x86-64 16 registros de 64 bits %rax, %rbx, %rcx, %rdx, %rdi, %rsi, %rsp, %rbp, %r8 a %r15 Acceso directo a 32 bits menos significativos Acceso directo a16 bits menos significativos Acceso directo a 8 bits menos significativos Registro %rsp es puntero a la pila No hay puntero base! 16 Registros x86-64 63 31 8 7 15 0 %rax %eax %ax %ah %al %rbx %ebx %bx %bh %bl %rcx %ecx %cx %ch %cl %rdx %edx %dx %dh %rsi %esi %si %sil %rdi %edi %di %dil %rbp %ebp %bp %bpl %rsp %esp %sp %spl %r8 %r8d %r8w %r8b %r15 %r15d %r15w %r15b %dl Ejemplo x86-32 y x86-64 Sea la función simple() en C long int simple(long int *xp, long int y) { long int t = *xp + y; *xp = t; return t; } Compilando para x86 de 32 bits gcc –m32 simple.c Compilando para x86 de 64 bits gcc –m64 simple.c ©2014 Mario Medina C. 2 Código x86-32 Compilando como Código x86-64 Compilando como gcc –S –m32 simple.c simple: pushl %ebp movl %esp, %ebp movl 8(%ebp), %edx movl (%edx), %eax addl 12(%ebp), %eax movl %eax, (%edx) leave ret gcc –S –m64 simple.c simple: addq (%rdi), %rsi movq %rsi, %rax movq %rsi, (%rdi) ret Código x86-64 tiene 4 instrucciones y 2 accesos a memoria vs. 8 instrucciones y 7 accesos a memoria para x86 Direccionamiento relativo al PC Contador de programa (instruction pointer) de 64 bits llamado %rip Direccionamiento inmediato suma una constante de 32 bits al contador de programa Acceso rápido a datos a ±231 de %rip add 0x234567(%rip), %rax Suma M[%rip + 0x234567] al registro %rax Nuevas versiones de mov movq S, D Mueve operando de 64 bits de S a D Operandos inmediatos limitados a 32 bits con extensión de signo movsbq S, D Mueve byte a quad word con extensión de signo movswq S, D Mueve word a quad word con extensión de signo movslq S, D Mueve double word a quad word con extensión de signo Nuevas versiones de mov movzbq S, D Mueve byte a quad word con extensión cero movzwq S, D Mueve word a quad word con extensión cero No existe instrucción movzlq Mover 32 bits a registro de 64 bits automáticamente limpia los 32 bits superiores movabsq I, R Nuevas versiones de pushl y popl pushq S Similar a pushl, pero para 64 bits R[%rsp] R[%rsp] – 8 M[R[%rsp]] S popq D Similar a popl, pero para 64 bits D M[R[%rsp]] R[%rsp] R[%rsp] + 8 Mueve valor inmediato de 64 bits a un registro ©2014 Mario Medina C. 3 Operaciones aritméticas de 64 bits Operaciones normales extendidas a 64 bits usando sufijo q Ejemplo de operaciones de 64 bits Código c long int func1(int x, int y) { long int t1 = (long) x + y; long int t2 = (long) (x + y); return t1 | t2; } addq, leaq, incq, salq, decq, etc. Instrucciones que generan resultados de 32 bits (addl) hacen 0 los 32 bits superiores Instrucciones que generan resultados de 8 ó 16 bits (addw) no modifican los otros bits Cast tiene precedencia sobre suma Primera suma es de 64 bits, segunda es de 32 bits Ejemplo de operaciones de 64 bits Código x86-64 # suponemos x esta en %edi, y en %esi func1: movslq %edi, %rdi # conv. x a long movslq %esi, %rsi # conv. y a long addq %rdi, %rsi # suma en 64 bits leal (%esi, %edi), %eax # suma x+y en 32 bits cltq # extiende %eax # a 64 bits orq %rsi, %rax # OR de 64 bits ret Operaciones aritméticas de 64 bits Instrucción Efecto Descripción imulq S R[%rdx]:R[%rax]SR[%rax] Multiplica con signo mulq S R[%rdx]:R[%rax]SR[%rax] Multiplica sin signo cltq R[%rax] SignExtend(R[%eax]) Convierte %eax a quad word cqto R[%rdx]:R[rax] SignExtend(R[%rax]) Convierte %rax a oct word idivq S R[%rdx]R[%rdx]:R[%rax] mod S División con signo R[%rax]R[%rdx]:R[%rax]S; divq S R[%rdx]R[%rdx]:R[%rax] mod S División sin signo R[%rax]R[%rdx]:R[%rax]S; Llamadas a funciones Instrucción callq almacena dirección de retorno de 64 bits en la pila Arquitectura x86-64 usa los registros para pasar hasta 6 argumentos en vez de la pila Reduce tráfico de datos desde y hacia memoria No es necesario crear marco de activación Sólo para almacenar variables locales No se usa un registro como puntero al marco de activación Paso de parámetros Número del argumento Operando (bits) 1 2 3 4 5 6 64 %rdi %rsi %rdx %rcx %r8 %r9 32 %edi %esi %edx %ecx %r8d %r9d 16 %di %si %dx %cx %r8w %r9w 8 %dil %sil %dl %cl %r8b %r9b Todo es relativo al registro %rsp ©2014 Mario Medina C. 4 Ejemplo Código C Ejemplo Código x86-64 void func2(long a1, long *a1p, int a2, int *a2p, short a3, short *a3p, char a4, char *a4p) { *a1p += a1; *a2p += a2; *a3p += a3; *a4p += a4; } func2: movq 16(%rsp), %r10 addq %rdi, (%rsi) addl %edx, (%rcx) addw %r8w, (%r9) movzbl 8(%rsp), %eax addb %al, (%r10) ret Convención de paso de parámetros Registros %rdi, %rsi, %rdx, %rcx, %r8 y %r9 son usados para pasar parámetros Registro %rax es el valor retornado por la función Registro %rsp es el puntero a la pila Registros %rbx, %rbp, %r12 a %r15 son Callee-Save Registros %r10 y %r11 son Caller-save # # # # # # # # a1 esta en %rdi a1p esta en %rsi a2 esta en %edx a2p esta en %rcx a3 esta en %r8w a3p esta en %r9 a4 esta en %rsp+8 a4p esta en %rsp+16 Marcos de activación en x86-64 Necesarios si Función usa demasiadas variables locales Algunas variables locales son vectores o estructuras Función calcula la dirección de alguna variable local usando operador de dirección & Función debe pasar args. via la pila a otra función Función necesita salvar algún registro callee-save Marco de función es de tamaño fijo Accesos son relativos a registro %rsp Movimiento condicional Movimiento condicional Instrucciones de movimiento condicional transfieren datos si se cumple una condición Instrucción Sinónimo Condición cmove S, R cmovz ZF Igual / Cero Si la condición no se cumple, no hay movimiento de datos Instrucciones de movimiento condicional reemplazan 2 instrucciones cmovne S, R cmovnz ~ZF Distinto / No cero Formato CMOVXX donde XX es una condición Condiciones posibles son similares a instrucciones setXX y saltos condicionales jXX Introducidas por Intel en Pentium Pro en IA32 Aprovechadas al máximo por AMD en AMD64 ©2014 Mario Medina C. Descripción cmovs S, R SF Negativo cmovns S, R ~SF No negativo cmovg S, R cmovnle cmovge S, R cmovnl ~(SF^OF)&~ZF Mayor (signed >) ~(SF^OF) Mayor o igual (signed >=) cmovl S, R cmovnge SF^OF Menor (signed <) cmovle S, R cmovng (SF^OF)|ZF Menor o igual (signed <=) cmova D cmovnbe ~CF &~ZF Superior (unsigned >) cmovae D cmovnb ~CF Superior o igual (unsigned >=) cmovb D cmovnae CF Inferior (unsigned <) cmovbe D cmovna CF|ZF Inferior o igual (unsigned <=) 5 Ejemplo de movimiento condicional Código C condicional Código x86 de 32 bits usando instrucción de movimiento condicional if (a == 5) x = y Suponga que %eax contiene a, %ebx contiene x y %ecx contiene y Código x86 de 32 bits es cmpl $5, %eax jnz Fin # # # # movl %ecx, %ebx Fin: Ejemplo de movimiento condicional Compara a con 5 Si no es igual, ir a Fin Copia y en x cmpl $5, %eax # Compara a con 5 cmovz %ecx, %ebx # Copia y en x Instrucciones de movimiento condicional Ejemplo de movimiento condicional Sea el siguiente código C v = (expr_test) ? expr_V : expr_F; Generalmente esto se compila como if (!expr_test) goto falso; v = expr_V; goto fin; Falso: v = expr_F; Fin: Permiten reducir la longitud del código Permiten evitar penalidades de predicción de salto causadas por saltos condicionales Acelera la ejecución de programas en procesadores que tienen pipelining Ejemplo de movimiento condicional Usando movimiento condicional, el código generado es similar a éste vt = expr_V; v = expr_F; t = expr_test; if (t) v = vt; Este último condicional se realiza en una sola sola instrucción de movimiento condicional vt se copia a v sólo si t es verdadera Movimiento condicional La gran ventaja de las instrucciones de movimiento condicional es que reducen el número de saltos Reduce la penalidad en procesadores segmentados En el primer caso, hay 2 saltos En el segundo caso, no hay saltos No es aplicable a casos en que evaluar las expresiones tengan efectos secundarios x = (xp) ? *xp : 0; ©2014 Mario Medina C. 6