Diferencia entre revisiones de «Apuntes primer parcial 03/10/2006 (Organización del Computador II)»

De Cuba-Wiki
(Edited by Palla)
Línea 24: Línea 24:


== Instruccion LEA ==
== Instrucción LEA ==


  lea reg, [reg1 + reg2*t + k]
  lea reg, [reg1 + reg2*t + k]
Línea 30: Línea 30:
Tiene el mismo formato que un modo de direccionamiento
Tiene el mismo formato que un modo de direccionamiento
Donde t es 1,2,4,8; k es un inmediato de 32 bits; y los registros son de 32 bits
Donde t es 1,2,4,8; k es un inmediato de 32 bits; y los registros son de 32 bits


== Pila ==
== Pila ==

Revisión del 03:21 4 oct 2006

Strings

Averigue el puntero/longitud a la meseta mas larga Meseta es repeticion de letras iguales

Se anidan dos ciclos/funciones/macros.

Macro interna longMeseta:

Dado esi (en strings, puntero al src, en gral), devuelve la longitud de la meseta q empieza en esi. Requiere: esi al comienzo de la meseta bit de direcciones en avanzar Asegura: esi en el caracter siguiente a la meseta ecx tiene la longitud del resto de la cadena ebx es la longitud de la meseta

Se puede hacer mediante la instruccion scas. Se usa un lodsb para levantar el 1er byte de la meseta, el scas para iterar, y un repe para iterar mientras sea igual. La longitud de la meseta es la diferencia entre el esi del final y el esi del ppio.

Se debe llamar a longMeseta para recorrer toda la cadena, en un ciclo externo.

while ecx>0
	longMeseta
	ebx= max(ebx, max_actual)


Instrucción LEA

lea reg, [reg1 + reg2*t + k]

Tiene el mismo formato que un modo de direccionamiento Donde t es 1,2,4,8; k es un inmediato de 32 bits; y los registros son de 32 bits

Pila

El push decrementa, el pop incrementa. Todas las variables al escribir un procedimiento deben ser locales y encontrarse en el stack. Las variables globales, con section data, son solo para programas (no se hace en el parcial!).


Numeros grandes

Para laburar con enteros grandes, se pueden hacer suposiciones sobre el tamaño maximo de los mismos. No hay que validar de mas en assembler, la idea es funciones rapidas.


Multiplicacion de numeros grandes por potencias chicas de 2

Sea el numero 08 00 CA FE Lo consideramos "grande" para este ejercicio

Lo queremos multiplicar por 2 En el primer byte uso un SHL/SAL 1 En los siguientes, RCL, rotate left circular

El shift saca el bit mas significativo y lo mete en el CF El RCL hace un shift, mete el CF en el menos significativo, y pisa el CF con el mas significativo q saco afuera El ROL pasa directamente del mas significativo al menos, y copia el mas significativo al CF

El SHR mete un cero en el mas significativo, y el SAL repite el 7mo bit. Tiran el bit menos significativo que sacaron en el CF. Para dividir hay que ir del dword mas significativo al menos.

Para multiplicar por 4, no conviene correr 2 veces el algoritmo anterior por los accesos a memoria Como se necesitarian 2 carry flag, se puede ir tirando los bits del carry a otro registro, haciendo RCL del reg que tiene el numero para cargar el carry, despues otro RCL contra el reg adicional para guardar ahi el carry, y asi sucesivamente. Antes de seguir a la proxima dword, se shiftea lo necesario para pasar los bits guardados de la parte mas alta a la mas baja. Otra posibilidad es guardar los bits mas significativos con operaciones logicas: copiar el registro y hacer un and con una mascara que deje solo los mas altos que se quieran guardar.


Multiplicar numeros grandes con signo

Para multiplicar numeros grandes, primero pasar los dos a positivo y despues multiplicar, y ver cual deberia ser el signo del resultado.

Para cambiar de signo, empiezo por el menos significativo y voy negando y sumando uno (el carry despues de la 1er dword). La negacion se puede hacerla en los registros, no negarlo en memoria. Hay que guardar el carry en ese caso para saber que sumar.


Multiplicar un numero grande por un registro de 32bit

Se tiene un numero grande en memoria, en esi el puntero. En ebx el numero por el que se quiere multiplicar. Cargo la parte baja en eax, multiplico por ebx y queda el resultado en edx:eax. En la 1er iteracion, se puede bajar eax directamente. La parte alta, edx, es necesario guardarla (x ej en ecx).

mov eax, [esi]
mul ebx
mov [edi], eax
mov ecx, edx

Luego hay que sumar eax y ecx antes de bajar a memoria. El carry que se produce por sumar ecx y edx hay que pasarlo a edx. Ese pasaje de carry NO puede producir carry, por el tamaño de los numeros.

(incPunteros)
mov eax, [esi]
mul ebx
add eax, ecx
adc edx, 0
mov [edi], eax
mov ecx, edx


Convencion C

Llamador

Primero, push de los parametros, del ultimo al primero. La convencion C no asegura que los parametros que se pasan no se modifican; de hecho se pueden usar como locales para la funcion llamada. No esta bien extraer informacion adicional a partir del estado de los parametros al retornar. Luego call (pushea instruction pointer, o program counter, y lo cambia a la direccion a la que salta)

Al retornar, el llamador debe hacer un add del esp para liberar el espacio reservado para los parametros. El resultado esta en eax, si no es void. Si es de 64 bits, gralmente esta en edx:eax.


Llamado

Push del ebp anterior. Modifica su propio ebp para apuntarlo al tope actual de la pila (mov ebp,esp). No es necesario guardar ebp y usarlo para acceder al stack frame, pero es recomendable. Se puede ebp como otro registro mas, NO esp. Se pushean los registros que deben salvarse (ebx, edi, esi), si van a usarse. Si no no es necesario. Se hace sub del esp lo necesario para reservar espacio para las variables locales o los out. Para direccionar a variables locales y a parametros, se direcciona sumando o restando a ebp. Ej: para ver el 1er parametro, [ebp+8].