Ejercicios parcialmente resueltos – Tema 2

Transcripción

Ejercicios parcialmente resueltos – Tema 2
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

Documentos relacionados