Ejercicio 2.1. El nivel de conocimiento necesario para desarrollar software depende, evidentemente del tipo de software. Indicar qué tipo de modelo (aplicaciones/sistemas) y a qué nivel (bajo/medio/alto) es necesario conocer para desarrollar el siguiente tipo de software: (a) Compilador: Sistemas / Alto (b) Depurador: Sistemas / Alto (c) Bootloader: Aplicaciones / Medio (d) Driver de dispositivo: Sistemas / Alto (e) Un servicio del S.O: Aplicaciones / bajo (f) Editor de texto: Aplicaciones / Bajo Ejercicio 2.2. ¿Por qué? Si un procesador A es mejor y más barato que B, si compras B eres subnormal. Ejercicio 2.3. El término “familia de microprocesadores” puede tener usos distintos en distintos fabricantes. En qué se diferencia el significado que hemos visto con el significado que se utiliza en http://ark.intel.com/ (comparación de procesadores Intel en el mercado actualmente). Es lo mismo :s, quizás este está centrado en el mercado Intel Ejercicio 2.4. Los tipos anteriores de compatibilidad también pueden aplicarse, salvando las distancias, a otras cosas. De las siguientes parejas de películas, que tipo de “compatibilidad”, de los tres que hemos visto, guardan entre ellas: 1. “Spaceballs” y “Star Wars” => Inclusión 2. “Star Wars” y “The Empire Strikes Back” => Inclusión 3. “Avatar” y “アバタ”. => Total Ejercicio 2.5. ¿Por qué otros nombres se conoce la arquitectura IA32? X86 Ejercicio 2.6. Cómo se podría mejorar el siguiente código: for (i=0; i<100; i++) for (j=0; i<1000; j++) if (Matriz[i][0]>Matriz[i][j]) Matriz[i][0]= Matriz[i][j] Para minimizar los accesos a memoria se podrían sacar a variables externas los accesos a la matriz(que son muy costosos tiempo de ejecución). (suponiendo que la condición de parada del segundo for es una errata. Si no ni pajolera idea xD). Ejercicio 2.7. Cuando entramos en Linux o Windows como root (o Administrador), ¿estamos ejecutando en nivel kernel? No necesariamente. Cuando ejecutamos un sistema operativo con permiso de administrador otorga poderes administrativos sobre el sistema operativo, no sobre la máquina. Otra cosa es que el acceso al modo administrador de un procesador sólo sea accesible desde un usuario con permisos de administración. Ejercicio 2.8. Realizar una prueba del trato amable del sistema operativo para aquellos programas que no respetan la memoria que tienen asignada: definir un puntero a entero, inicializarlo con alguna dirección arbitraria e intentar escribir en esa dirección. Se intenta escribir en una posición de memoria arbitraria, por lo que el sistema operativo bloquea la acción. Ejercicio 2.9. ¿para qué sirven estos últimos 5 grupos de registros? Registros de control de memoria virtual: GDTR-LDTR: Global/Local Descriptor Table Register. EFLAGS: Registro que contiene el estado actual del procesador. CR0-4: Registros de control del procesador DB0-7: Registros de debug del procesador. MSR: Usados para facilitar el debug, testeabilidad, trazabilidad y rendimiento Ejercicio 2.10. ¿Qué hace el indicador register en C? ¿permite indicar explícitamente qué registro se usará para una variable? Register en C es utilizado para indicar que una variable será almacenada en un registro del procesador (sin poder saberse donde ni especificar su destino). Sólo es válido para ámbitos locales, parámetros de funciones y variables automáticas. Ejercicio 2.11. En los procesadores de 32 bits modernos, un registro de propósito general se puede usar en todas las instrucciones del procesador. En el IA32 esto no es cierto. ¿Se pueden usar las instrucciones MOV, IDIV, ADD, STOS con cualquiera de los registros del procesador? Consultarlo en [INT00b] ("Instruction Set Reference Manual" del IA32 que viene en la bibliografía). Ejercicio 2.12. Cuando ponemos un "breakpoint" en una línea de programa C/C++, el depurador de Visual Studio se para en esa instrucción ¿antes o después de ejecutarla? ANTES de ejecutarla. Ejercicio 2.13. Realizar otra prueba del trato amable del sistema operativo para aquellos programas que no respetan las reglas de protección: intentar deshabilitar las interrupciones. Se puede hacer insertando, en cualquier programa C, el siguiente bloque de ensamblado en línea: __asm { // Cuidado, __ lleva dos caracteres '_' delante de asm // Poner aquí la instrucción que desactiva interrupciones (pone IF a 0) } El sistema operativo lanza el mensaje: Excepción no controlada en 0x004114fe en Tema 2.exe: 0xC0000096: Privileged instruction. Ejercicio 2.14. Qué pasaría si el sistema operativo dejara ejecutar el programa anterior. Se desabilitarían las interrupciones al procesador, por lo que el ordenador se volvería “monotarea”. Ejercicio 2.15. El bit de control DF (Direction Flag), ¿está también protegido?. Comprobarlo modificando el código anterior para ponerlo a 1. No está protegido. Se puede comprobar utilizando la orden ensamblador cld; Ejercicio 2.16. La palabra dword se usa en el IA32 para designar datos de 32 bits. ¿Es así en otros procesadores de 32 bits, como MIPS o MC68000 o ARM? Ejercicio 2.17. ¿En qué formato se codifican los números enteros con signo? Ejercicio 2.18. ¿Existen los tipos de la figura 2.9 en los lenguajes de programación que conoces? Ejercicio 2.19. Rellenar la siguente tabla con los tipos equivalentes en distintos lenguajes de programación (hacer tras la práctica 1). Tipos del procesador Byte signed integer Byte unsigned integer Word signed integer Word unsigned integer Dword signed integer Dword Pointer unsigned integer Tipo para C Para Java Para C# (avanzado) Ejercicio 2.20. El procesador IA32 ¿Es little-endian o big-endian? (hacer tras la práctica 1) Ejercicio 2.21. Una triste historia real. Ejecutamos el siguiente programa en un PC: int SiguenteDato; … WriteFile( FICHERO, &SiguienteDato, 4, … // Escribo el contenido // de SiguienteDato en un archivo. … El programa guarda datos en una memoria USB. Usamos el mismo programa en un MAC G5 (cambiando la función WriteFile por la equivalente en OS X, el sistema operativo del MAC, y recompilándolo, por supuesto.). Al cabo de un tiempo, hay varios ficheros en la USB que contienen datos incomprensibles cuando se usa otra parte de este programa para leerlos ¿Qué ha pasado? Ejercicio 2.22. De los tipos simples que usan los lenguajes de alto nivel, como C, Java o C#, ¿qué tipos faltan en esta sección? Bool y char Ejercicio 2.23. ¿Qué significa, en la terminología Intel, el término “dirección efectiva”? Ver la sección 5.3 de [INT00]. Offset = Base(Registro) + (Index(registro)*Scale) + Desplazamiento Ejercicio 2.24. ¿Se utilizan todos los modos de direccionamiento que vienen en el manual de Intel? Señalar, para cada modo, cuál es la primera instrucción que lo utiliza. Ver la sección 5.3 de [INT00]. Registro: Línea 1 Inmediato: Linea 1 Relativo al IP(Salto): ¿? Memoria: Línea 3 Ejercicio 2.25. ¿A qué dirección de memoria accede la próxima instrucción a ejecutar? 0x00833DFC(instrucción de salto). Ejercicio 2.26. ¿Cuántos bytes de diferencia hay entre el código de operación mov entre registros y un mov que mueva a memoria? ¿Por qué? Dependiendo del tipo de instrucción puede haber una diferencia de hasta 2 bytes. Ejercicio 2.27. ¿Todas las instrucciones que acceden a memoria ocupan lo mismo? ¿Por qué? No, algunas hacen uso de un desplazamiento o no, de uno o dos registros, de escala... Ejercicio 2.28. Mirar los detalles del funcionamiento de MOV en [INT00]. ¿Fuente y destino deben tener el mismo tamaño? Sí Ejercicio 2.29. El procesador IA32 ¿Es little-endian o big-endian? (hacer tras la práctica 1) Ejercicio 2.30. ¿Existe la siguiente instrucción? MOV dword ptr[0x2230], dword ptr[0x2250] ;Copia [0x2230] el contenido de [0x2250] a No Ejercicio 2.31. ¿Y ésta? dword ptr[0x2230], 0 ; Copia un 0 en la dirección [0x2230] Sí Ejercicio 2.32. ¿Cuáles son esas instrucciones MOV que implementan ambas asignaciones? Var1 = 10; // Almacena una constante en una variable => MOV [var1], 10 Var2 = Var1; // Almacena una variable a otra => MOV AX, [var1] - MOV [var2] EAX Ejercicio 2.33. ¿Se sigue usando la instrucción mov si definimos Var1 como char y Var2 como int? No, puesto que son instrucciones de tamaño distinto y habría que “convertirlas”. Ejercicio 2.34. Escribir el código máquina equivalente a las siguientes instrucciones C, suponiendo que Entero es int, Entero16 es short y Caracter es char (Modificar la función AritmeticaSinFronteras, en [EJE_T2]): C Desensamblado Entero= Entero + 10; mov eax,dword ptr [entero] add eax,0Ah mov dword ptr [entero],eax // Suma Entero16= 12 – Entero16; // Resta Entero= - Caracter; // Negación Entero++; // Incremento Caracter--; // Decremento Entero= Entero*10; // Multiplicación movsx eax,word ptr [entero16] mov ecx,0Ch sub ecx,eax mov word ptr [entero16],cx movsx eax,byte ptr [caracter] neg eax mov dword ptr [entero],eax mov eax,dword ptr [entero] add eax,1 mov dword ptr [entero],eax mov al,byte ptr [caracter] sub al,1 mov byte ptr [caracter],al mov eax,dword ptr [entero] imul eax,eax,0Ah mov dword ptr [entero],eax Entero= Entero/10; // División Entero= Entero*8; // Multiplicación mov eax,dword ptr [entero] cdq mov ecx,0Ah idiv eax,ecx mov dword ptr [entero],eax mov eax,dword ptr [entero] shl eax,3 mov dword ptr [entero],eax Ejercicio 2.35. Si las variables Entero, Entero16 y Caracter se definen sin signo, ¿cambian alguna de las instrucciones anteriores? Cambia sólo la división: mov xor mov div mov eax,dword ptr [entero] edx,edx ecx,0Ah eax,ecx ptr [entero],eax Ejercicio 2.36. En http://en.wikipedia.org/wiki/Bitwise_operation tenemos una definición de operaciones bitwise que, si pinchamos la versión en español del artículo nos envía a http://es.wikipedia.org/wiki/Operador_a_nivel_de_bits. ¿están hablando de lo mismo en ambos artículos? ¿Cuál es la versión correcta? Bitwise operation consiste en aplicar una operación lógica bit a bit entre dos números. Ejercicio 2.37. Escribir el código C equivalente a las siguientes instrucciones en ensamblador, definiendo el tipo de variables adecuadas (tipo y variable local o global), suponiendo que Entero es int, Entero16 es short y Caracter es char 33. C Código Máquina X == 8 and dword ptr [ebp-4], 8 movzx eax, byte ptr [833E20h] not eax mov byte ptr [ebp-20], al [ebp-8]>>2; // Manteniendo el bit de signo. sar byte ptr [ebp-8], 2 [ebp-12]>>2; shr byte ptr [ebp-12], 2 int x = 0, y = 0, z = 0; xor eax, eax mov dword ptr [ebp-4], eax mov dword ptr [ebp-8], eax mov dword ptr [ebp-12], eax Ejercicio 2.38. ¿Qué diferencia hay entre las instrucciones NEG y NOT? (Hacer al final) NEG = Complemento a 2 de un número NOT = Complemento a 1 de un número. Ejercicio 2.39. Si ejecutamos la instrucción MOV EAX, ECX ¿hay algún valor de ECX que ponga ZF a 1? ¿Hay algún valor de ECX que ponga SF a 1? ZF = 1 <=> ECX == 0. SF = 1 <=> cualquier número negativo que tenga ECX. Ejercicio 2.40. Si ejecutamos mov eax, 0 add al, 80h add ax, 8000h add eax, 80000000h ¿Cuáles de las instrucciones ADD activan el bit SF? ¿Por qué? La segunda. Ejercicio 2.41. ¿Cómo se sumarían dos números de 128 bits? ¿Cómo se restan? (mirar en el manual cómo funcionan las instrucciones de suma y resta necesarias). Ejercicio 2.42. Para los siguientes ejercicios usaremos la función ImprimeFibonacci, en [EJE_T2]. ¿En qué iteración se produce un desbordamiento? ¿En qué iteración se produce el desbordamiento si cambiamos int por char? INT => Cuando se activa OV, es decir, el bit de overflow. En la iteración 45. CHAR => Cuando se activa OV, es decir, el bit de overflow. En la iteración 11. Ejercicio 2.43. ¿Qué bit del registro de estado se ha activado cuando se produce el desbordamiento? OF = OV // signed CF = CY // unsigned Ejercicio 2.44. Repetir los dos ejercicios anteriores con unsigned char. En la iteración 12. Ejercicio 2.45. ¿Se ha detectado el error en la compilación o en la ejecución del programa, o en ningún sitio? En ningún sitio. Ejercicio 2.46. Una de las operaciones aritméticas más costosas en tiempo de ejecución es la multiplicación. ¿hay instrucciones de multiplicación (del IA32) en la función IniciaMatriz, en [EJE_T2]? int Matriz[NRO_FILAS][NRO_COLUMNAS]; int k, p; void IniciaMatriz(void){ 00411B70 push ebp 00411B71 mov ebp,esp 00411B73 sub esp,0C0h 00411B79 push ebx 00411B7A push esi 00411B7B push edi 00411B7C 00411B82 00411B87 00411B8C for 00411B8E 00411B98 00411B9A 00411B9F 00411BA2 00411BA7 00411BAE 00411BB0 00411BBA 00411BBC 00411BC1 00411BC4 00411BC9 00411BD0 00411BD2 00411BD7 00411BDA 00411BE0 00411BEB 00411BED } lea edi,[ebp-0C0h] mov ecx,30h mov eax,0CCCCCCCCh rep stos dword ptr es:[edi] (k=0; k< NRO_FILAS; k++) mov dword ptr [k (418168h)],0 jmp IniciaMatriz+37h (411BA7h) mov eax,dword ptr [k (418168h)] add eax,1 mov dword ptr [k (418168h)],eax cmp dword ptr [k (418168h)],0Ah jge IniciaMatriz+7Fh (411BEFh) for (p=0; p< NRO_COLUMNAS; p++) mov dword ptr [p (418714h)],0 jmp IniciaMatriz+59h (411BC9h) mov eax,dword ptr [p (418714h)] add eax,1 mov dword ptr [p (418714h)],eax cmp dword ptr [p (418714h)],1Eh jge IniciaMatriz+7Dh (411BEDh) Matriz[k][p]= 1; mov eax,dword ptr [k (418168h)] imul eax,eax,78h mov ecx,dword ptr [p (418714h)] mov dword ptr Matriz (418170h)[eax+ecx*4],1 jmp IniciaMatriz+4Ch (411BBCh) jmp IniciaMatriz+2Ah (411B9Ah) Ejercicio 2.47. Comprobar esto desensamblando el bucle while de la función ImprimeFibonacci, en [EJE_T2] ¿Dónde están los saltos condicionales e incondicionales en un bucle while? Bucle while “resumido” while (i<ULTIMO_NUMERO) 004119D9 cmp dword ptr [i (418644h)],32h 004119E0 jae ImprimeFibonacci+61h (4119F1h) { i++; 004119E2 mov eax,dword ptr [i (418644h)] 004119E7 add eax,1 004119EA mov dword ptr [i (418644h)],eax } 004119EF jmp ImprimeFibonacci+49h (4119D9h) } Ejercicio 2.48. Las reglas de selección de salto se pueden comprobar en las dos primeras instrucciones if de la función SiNoNose ([EJE_T2]) ¿Cuál es la condición que se testea en C y cómo se traduce en ensamblador? Ejercicio 2.49. Sin embargo, las reglas de selección de saltos condicionales tienen algunas limitaciones ¿Cuál es el resultado de la comparación if (ConSigno<SinSigno) en la función SiNoNose ([EJE_T2]), si definimos ambas variables como char y unsigned char, respectivamente? Contestar esta pregunta antes y después de ejecutar la función. ¿Cuál es el problema? Ejercicio 2.50. ¿Por qué existen distintas reglas de implementación? Una pregunta con respuesta similar: ¿Por qué existen distintas marcas de coches? A pesar de que el resultado final sea el mismo, existen distintas formas de hacer cada cosa. Cada fabricante utiliza la que considera mejor/más le gusta. Ejercicio 2.51. Analizar el comportamiento de las instrucciones CALL y RET en la función funcion1 ([EJE_T2]). En primer lugar se carga en la pila los parámetros de la función a la que se va a llamar. Se llama a la instrucción call, que guarda la siguiente dirección a la que saltar y salga a la función destino. Cuando la función destino se ha ejecutado, mediante ret se vuelve al punto anteriormente guardado. Se incrementa el puntero de pila la cantidad de bytes que ocupen los parámetros de la función Ejercicio 2.52. Si cambiamos en funcion1 la línea unsigned int Numero= 10; por unsigned int Numero= 10000;, tendremebos un error de overflow. ¿Qué produce el error? ¿Las operaciones aritméticas con enteros son las que producen el error de overflow? Contestar antes y después de ejecutar la función. Antes: El overflow se produce porque el resultado “no cabe” en un unsigned int. Despues: Stack Overflow Ejercicio 2.53. Escribir la función CalculaMax(… y la llamada del ejemplo anterior suponiendo que Val es int y Ref es char. ¿Qué instrucciones usa el IA32 para poner los parámetros en la pila? Añade los elementos en la pila mediante la instrucción push. Ejercicio 2.54. Cómo funciona la instrucción PUSH. Describir su funcionamiento. Decrementa la dirección del puntero a pila y añade en esta posición el valor que se le indique. Ejercicio 2.55. ¿Cómo quita el IA32 los parámetros tras la llamada? Al hacer la llamada se hacen tantos push como parámetros tenga la función y se guardan en registros. Antes de salir se hacen tantos pop como parámetros tenga la función. Una vez se ha hecho el RET, se hacen tantos pop como parámetros se han pasado a la función. Ejercicio 2.56. Repetir el ejercicio anterior para la línea Resultado= abs(Val). El funcionamiento es el mismo, pero con dos llamadas a funciones que modifican la pila. Ejercicio 2.57. ¿Cómo funciona la instrucción POP? Describir su funcionamiento. Saca el elemento de la cima de la pila y lo guarda en la posición que indique el parámentro que acompaña a la instrucción. Ejercicio 2.58. ¿Cómo devuelven los resultados las funciones anteriores? El resultado de una función se guarda en EBP Ejercicio 2.59. Repetir el ejercicio anterior para Resultado= _abs64(Val); (hay que definir Resultado como __int64). Ejercicio 2.60. Tras estudiar atentamente la aritmética de punteros en C, a un programador se le ocurre un innovador método para inicializar todas las variables locales a 0. Pretende demostrar su gran dominio de la aritmética de punteros. ¿Por qué no funciona? Dar al menos 3 razones. void Ocurrencia(int Parametro) { int Numero1; //<-- Primera variable a inicializar int Numero2; int Numero3; int * PEntero; int Res; // <- última variable a inicializar int NroBytes; NroBytes= (&Res - &Numero1) *sizeof(int); // Nro. De enteros en el bloque * Tamaño de los enteros. memset(&Numero1, 0, NroBytes); // Dirección inicial del bloque, Valor con el que se rellena (char), Nº bytes a rellenar Las variables no tienen porqué estar continuas en memoria. El tamaño de un puntero no tiene porqué ser del mismo tamaño de una variable entera. (FALTA UNA) Ejercicio 2.61. Supongamos que en el programa del ejercicio 2.60, las dos últimas líneas del programa tienen el siguiente error: PEntero= &Res; *(PEntero + Numero1) =0; ¿Qué efecto tiene si suponemos que Res es la primera variable local de la pila y Numero1 vale 3? Ejercicio 2.62. ¿Y si Numero1 vale 2 ó 4? Ejercicio 2.63. ¿Puede haber algún efecto adverso para la función llamante si Numero1 es negativo? Ejercicio 2.64. Un desensamblador (bastante malo) muestra la siguiente línea en pantalla. ¿Cuántas interpretaciones se pueden dar de esta información? (O, dicho de otra forma, cuantas respuestas distintas tiene la pregunta ¿qué hace esta instrucción?) MOV [0x2230], 0 Puede referirse a un segmento o a una zona concreta de memoria en un procesador de 20 bits. Ejercicio 2.65. ¿Qué ocurre si definimos Var1 como unsigned char (char sin signo) y Var2 como unsigned int (int sin signo)? Unsigned char Var1 = 10; // Almacena una constante en una variable unsigned int Var2 = Var1; // Almacena una variable a otra El valor de la variable destino es mayor que el valor de la variable origen, por lo que habrá que “completarlo”. Ejercicio 2.66. La mayoría de las PDAs existentes el mercado tienen un procesador de la familia ARM y sistema operativo basado en Windows CE. El entorno de desarrollo para Windows CE es Visual Studio, lo que permite portar de una forma relativamente sencilla software escrito originariamente para PCs con Windows. Sin embargo hay un tipo de programas que suelen dar bastante dificultades: los de procesado de audio y vídeo, sobre todo en tiempo real: los programas portados son mucho más lentos que los programas originales ¿A qué puede ser debido esto? Los procesadores ARM de PDA suelen ser mucho más lentos y tener menos memoria que los equivalentes tecnológicos en PC. Los sistemas en tiempo real por lo habitual suelen trabajar mucho con memoria, por lo que hay un cuello de botella considerable. Ejercicio 2.67. En las PDAs y teléfonos móviles con Windows CE (Mobile) tanto el sistema operativo como las aplicaciones ejecutan en modo kernel ¿es porque el procesador (familia ARM/ARM920/ARMv4) tiene un sólo nivel de ejecución? ¿Por qué es? Ejercicio 2.68. Si modificamos el bit DF en un programa Windows con ventanas, posiblemente fallará. ¿Por qué? ¿Qué hace este bit? The direction flag is a flag that controls the left-to-right or right-to-left direction of string processiong stored in the FLAGS REGISTER on all x86 compatible CPU's. Ejercicio 2.69. ¿Por qué, si modificar los bits DF e IF puede producir errores, sólo está protegido IF? This flag is used to determine the direction (forward or backward) in which several bytes of data will be copied from one place in the memory, to another. The direction is important mainly when the original data position in memory and the target data position overlap. Desactivar interrupciones es mucho más comprometido que cambiar el bit DF. En programas donde se hace copia intensiva de memoria es interesante cambiar el valor de este bit. Ejercicio 2.70. Una anomalía que se da en algunos lenguajes de programación: se puede definir una variable de tipo int y usarla en una operación & (bitwise AND). ¿por qué puede considerarse esto una anomalía? Ejercicio 2.71. Que instrucciones del IA32 usan los tipos de la figura 2.9. Ejercicio 2.72. La figura 2.4 parece indicar que los registros de segmento deberían tener todos los mismos valores. Comprobar si esto es así en un programa real. Ejercicio 2.73. En el IA32, las instrucciones de punto flotante o las MMX, ¿Pueden considerarse otros modelos de programación?¿Por qué? Sí, puesto que son extensiones hechas para operar sobre otro tipo de datos “emulados”. Ejercicio 2.74. ¿Hay otros procesadores en los que se den modelos de programación “paralelos”? Por supuesto, todos los vistos en la asignatura ASP2, por ejemplo. Ejercicio 2.75. En aritmética modular (enteros con módulo), puede producirse un error por desbordamiento (overflow) si el resultado de una operación no cabe en el tamaño de datos de destino. Escribir en C algún ejemplo de desbordamiento al hacer una asignación. ¿Detecta el compilador C, en tiempo de ejecución, estos errores? ¿Este es un problema de C o se da en otros lenguajes de programación? Ejercicio 2.76. Escribir código que detecte "a mano" un error de desbordamiento al pasar un int a un char. bool desbordamiento(int numero){ if(numero > 2^8) return true; else return false; } Ejercicio 2.77. Para los tipos agregados de C/C++ (estructuras y objetos), ¿la asignación se implementa por hardware en el IA32? Usar los ejemplos de las funciones AsignaEstructuras y AsignaObjetos, en [EJE_T2]. No, todo este mecanismo se hace mediante emulación (es decir, descomposición en varias instrucciones más sencillas). Ejercicio 2.78. La instrucción LEA se puede ver si, en la función AsignaTiposSimples de en [EJE_T2], definimos la variable Caracter como local. Entonces la asignación Puntero= &Carácter se implementa con LEA. ¿Cómo funciona esta instrucción? Fuentes de información: el manual de Intel y el código desensamblado. LEA calcula la dirección efectiva del segundo parámetro y la guarda en el primero. Ejercicio 2.79. Las instrucciones movimiento de la sección 2.8, las llamadas "menos comunes que MOV" (MOVSX, MOVZX y LEA), ¿cómo de menos comunes son? Mirar cuanto se utilizan en un programa C. Receta: • Crear o abrir un proyecto con código C/C++. • Configurar el proyecto (C++ Archivos de resultados) para que genere archivos .asm de cada archivo .c o .cpp. • Compilar. Ejercicio 2.80. Buscar los nombres de estas instrucciones en los archivos .asm (Visual Studio tiene una herramienta “buscar en archivos”. Ejercicio 2.81. Las instrucciones IMUL (multiplicación con signo) y MUL (multiplicación sin signo) ¿tienen el mismo formato? Ejercicio 2.82. Para la instrucción de suma (ADD), ¿existen también versiones con signo y sin signo? ¿Por qué? Recordar las propiedades de los números en complemento a 2. No, se utiliza la misma instrucción. Como la ALU no hace restas sino sumas, el complemento a dos de un número ayuda a hacer restas (que no es más que añadirle un signo al número). Ejercicio 2.83. Todos los problemas detectados hasta el ejercicio 2.45 con el desbordamiento, ¿ocurrentambién en otros lenguajes de programación que conozcas, como puede ser Java? No puesto que java hace conversiones dinámicas entre tipos. Ejercicio 2.84. ¿Cómo se puede detectar un desbordamiento en la función ImprimeFibonacci, en [EJE_T2]? Cuando el resultado empieza a dar números negativos. Ejercicio 2.85. Si en la función SinoNose de [EJE_T2] quitamos los comentarios del bucle while ¿tenemos un error? Contestar antes y después de ejecutar con el depurador. Antes: Error porque se entra en bucle infinito. Después: Entra en un bucle infinito, aunque la condición es un poco rara. Ejercicio 2.86. Para todos los ejercicios de análisis de pila se han desactivado dos características de la generación de código de Visual Studio (activas por defecto en compilación en modo “Debug”): 1. Chequeo de la pila. 2. Información de tipo depuración de tipo “Base de datos de programa para Editar y continuar (/ZI”. Uno de los errores más habituales es desactivar la primera y no desactivar la segunda. ¿Qué pasaría en ese caso en los ejercicios 2.61 y 2.62? ¿Qué pasaría cuando compiláramos el programa en modo “Release”? IA32 Flag Set Value OF Overflow OV = 1 DF Direction UP = 1 IF Interrupt EI = 1 SF Sign PL = 1 ZF Zero ZR = 1 AF Auxiliary Carry AC = 1 PF Parity PE = 1 CF Carry CY = 1