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

De Cuba-Wiki
(Agregué acentos y detalles menores. Javier)
Línea 1: Línea 1:
== Strings ==
== Strings ==


Averigue el puntero/longitud a la meseta mas larga
Averigüe el puntero/longitud a la meseta mas larga
Meseta es repeticion de letras iguales
Meseta es repetición de letras iguales


Se anidan dos ciclos/funciones/macros.  
Se anidan dos ciclos/funciones/macros.  
Línea 15: Línea 15:
ebx es la longitud de la meseta
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 puede hacer mediante la instrucción 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.
Se debe llamar a longMeseta para recorrer toda la cadena, en un ciclo externo.
Línea 33: Línea 33:
== Pila ==
== Pila ==


El push decrementa, el pop incrementa.
El push decrementa el esp, el pop incrementa. Nunca hay que pushear/popear registros o datos que no sean de 32 bits.
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!).
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 ==
== Números 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.
Para laburar con enteros grandes, se pueden hacer suposiciones sobre el tamaño máximo de los mismos que surjan del contexto de uso. No hay que validar de más en assembler, la idea es funciones rapidas.




==== Multiplicacion de numeros grandes por potencias chicas de 2 ====
==== Multiplicación de números grandes por potencias chicas de 2 ====


Sea el numero 08 00 CA FE
Sea el numero 08 00 CA FE
Línea 51: Línea 51:
En los siguientes, RCL, rotate left circular
En los siguientes, RCL, rotate left circular


El shift saca el bit mas significativo y lo mete en el CF
El shift saca el bit más 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 RCL hace un shift, mete el CF en el menos significativo, y pisa el CF con el más significativo q saco afuera
El ROL pasa directamente del mas significativo al menos, y copia el mas significativo al CF
El ROL pasa directamente del más significativo al menos, y copia el más significativo al CF


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


Para multiplicar por 4, no conviene correr 2 veces el algoritmo anterior por los accesos a memoria
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.
Como se necesitarian 2 carry flag, se puede ir tirando los bits del carry a otro registro, haciendo RCL del reg que tiene el número para cargar el carry, después otro RCL contra el reg adicional para guardar ahí el carry, y así sucesivamente. Antes de seguir a la proxima dword, se shiftea lo necesario para pasar los bits guardados de la parte más alta a la más 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.
Otra posibilidad es guardar los bits más significativos con operaciones lógicas: copiar el registro y hacer un and con una máscara que deje solo los más altos que se quieran guardar. Aproximadamente se debería hacer lo siguiente:


xor eax, eax
ciclo:
  mov ebx, [esi]
  mov edx, ebx
  and edx, f6000000 ;Máscara con cinco 1s y el resto ceros
  shr eax, 27
  shl ebx, 5
  or ebx, eax
  mov eax, edx
loop ciclo


==== 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.
==== Multiplicar números grandes con signo ====


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.
Para multiplicar números grandes, primero pasar los dos a positivo y después multiplicar, y ver cual debería ser el signo del resultado y cambiarlo acordemente.


Para cambiar de signo números grandes, empiezo por el menos significativo y voy negando y sumando uno (el carry después de la 1er dword). La negación se puede hacer en los registros, no hace falta negarlo en memoria. Hay que guardar el carry en ese caso para saber qué 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).  
==== Multiplicar un número grande por un registro de 32bit ====
 
Se tiene un número grande en memoria, en esi el puntero. En ebx el número 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 iteración, se puede bajar eax directamente. La parte alta, edx, es necesario guardarla (x ej en ecx).  


  mov eax, [esi]
  mov eax, [esi]
Línea 80: Línea 91:
  mov ecx, edx
  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.
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 números.


  (incPunteros)
  (incPunteros)
Línea 91: Línea 102:




== Convencion C ==
== Convención C ==


==== Llamador ====
==== Llamador ====


Primero, push de los parametros, del ultimo al primero.
Primero, push de los parámetros, del último 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.  
La convención C no asegura que los parámetros que se pasan no se modifican; de hecho se pueden usar como locales para la función llamada. No está bien extraer información adicional a partir del estado de los parámetros al retornar.  
Luego call (pushea instruction pointer, o program counter, y lo cambia a la direccion a la que salta)
Luego call (pushea instruction pointer, o program counter, y lo cambia a la dirección a la que salta).


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




Línea 106: Línea 117:


Push del ebp anterior.
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.
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 usar ebp como otro registro más, NO el esp.
Se pushean los registros que deben salvarse (ebx, edi, esi), si van a usarse. Si no no es necesario.
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.
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.
Para direccionar a variables locales y a parametros, se direcciona sumando o restando a ebp.
Ej: para ver el 1er parametro, [ebp+8].
Ej: para ver el 1er parametro, [ebp+8].

Revisión del 03:36 4 oct 2006

Strings

Averigüe el puntero/longitud a la meseta mas larga Meseta es repetición 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 instrucción 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 esp, el pop incrementa. Nunca hay que pushear/popear registros o datos que no sean de 32 bits. 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!).


Números grandes

Para laburar con enteros grandes, se pueden hacer suposiciones sobre el tamaño máximo de los mismos que surjan del contexto de uso. No hay que validar de más en assembler, la idea es funciones rapidas.


Multiplicación de números 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 más 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 más significativo q saco afuera El ROL pasa directamente del más significativo al menos, y copia el más significativo al CF

El SHR mete un cero en el más 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 más 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 número para cargar el carry, después otro RCL contra el reg adicional para guardar ahí el carry, y así sucesivamente. Antes de seguir a la proxima dword, se shiftea lo necesario para pasar los bits guardados de la parte más alta a la más baja. Otra posibilidad es guardar los bits más significativos con operaciones lógicas: copiar el registro y hacer un and con una máscara que deje solo los más altos que se quieran guardar. Aproximadamente se debería hacer lo siguiente:

xor eax, eax
ciclo:
 mov ebx, [esi]
 mov edx, ebx
 and edx, f6000000 ;Máscara con cinco 1s y el resto ceros
 shr eax, 27
 shl ebx, 5
 or ebx, eax
 mov eax, edx
loop ciclo


Multiplicar números grandes con signo

Para multiplicar números grandes, primero pasar los dos a positivo y después multiplicar, y ver cual debería ser el signo del resultado y cambiarlo acordemente.

Para cambiar de signo números grandes, empiezo por el menos significativo y voy negando y sumando uno (el carry después de la 1er dword). La negación se puede hacer en los registros, no hace falta negarlo en memoria. Hay que guardar el carry en ese caso para saber qué sumar.


Multiplicar un número grande por un registro de 32bit

Se tiene un número grande en memoria, en esi el puntero. En ebx el número 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 iteración, 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 números.

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


Convención C

Llamador

Primero, push de los parámetros, del último al primero. La convención C no asegura que los parámetros que se pasan no se modifican; de hecho se pueden usar como locales para la función llamada. No está bien extraer información adicional a partir del estado de los parámetros al retornar. Luego call (pushea instruction pointer, o program counter, y lo cambia a la dirección a la que salta).

Al retornar, el llamador debe hacer un add del esp para liberar el espacio reservado para los parámetros. El resultado está en eax, si no es void. Si es de 64 bits, generalmente está 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 usar ebp como otro registro más, NO el 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].