Parcial del 10/10/06 (Organización del Computador II)

De Cuba-Wiki
Saltar a: navegación, buscar
Back.png Volver a la página de la materia

Ejercicio 1 (IA32)[editar]

Codigo ASM de las funciones Nota a tener en cuenta: tal vez si no hubiese usado las macros que recomendo Tute me hubiese salido todo mas facil...


; Definiciones para Windows
%ifdef win32
	%define SumaMiniI			_SumaMiniI
	%define RestaNxDI 			_RestaNxDI
	%define malloc				_malloc
%endif

; Tal como le prometimos a C, aca estan las funciones
global 			RestaNxDI
global 			SumaMiniI

; El malloc lo tengo definido afuera
extern 			malloc

; Comienzo del codigo
section .text

;-------------------------------------------------------------------
; Macros que tute recomendo hacer
;-------------------------------------------------------------------
; Inicio del stack frame
%macro SF_ini	0
	push 		ebp
	mov			ebp,	esp
	push 		esi
	push 		edi
	push 		ebx
%endmacro

; Fin del stack frame
%macro SF_fin	0
	pop ebx
	pop edi
	pop esi
	pop ebp
	ret
%endmacro

; Lee un NGde de una posicion de memoria y asigna su tam a %1 y su r a %2
%macro LevantarNGde		3
	%define		reg_tam		%1
	%define		reg_r		%2
	%define		pNGde		%3
	mov		dword		reg_tam,	[pNGde]
	mov		dword		reg_r,		[pNGde + 4]
%endmacro

; Levanta un NGde pero de tam solo 1, 2 o 4 apuntado por %2 y deja su correspondiente numero de 32 bits en reg_valor
%macro LevantarNGdeMini		2
	%define		reg_valor	%1
	%define		pNGde		%2
	; Levanto el NGde...
	LevantarNGde	eax,		ecx,		pNGde
	
	; ...y me fijo como expandir el signo segun el tamaño con el que vino
	;xor		reg_valor,	reg_valor
	cmp		eax,		2
	jl		%%_uno
	je		%%_dos
		%%_cuatro:
			mov		reg_valor,		[ecx]
			jmp		%%_fin
		%%_dos:
			mov		ax,		[ecx]
			cwde
			mov		reg_valor,		eax
			jmp		%%_fin
		%%_uno:
			mov		al,		[ecx]
			cbw
			cwde
			mov		reg_valor,		eax
	%%_fin:
%endmacro

; Crea un nuevo NGde de tamaño %1. Deja a eax apuntandolo y en edi a r
%macro NuevoNGde	1
	%define	tam			%1
	; Pido para r
	push	dword		tam
	call	malloc
	add		esp,		4
	mov		edi,		eax
	; Pido para el NGde
	push	dword		8
	call	malloc
	add		esp,		4
	; Le informo cual es su tamaño y adonde tiene su numero (r)
	mov		dword		[eax],		tam
	mov		dword		[eax + 4],	edi
%endmacro

;-------------------------------------------------------------------


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	NGde* SumaMiniI(Ngde *sumando1, NGde *sumando2)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SumaMiniI:
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	; eax = ret
	; ebx = sumando1 (alto)
	; ecx = sumando2 (bajo)
	; edx = sumando2 (alto)
	; edi = ret->r
	; esi = sumando1 (bajo)
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	
	SF_ini
	
	; Cargo los 2 sumandos de parametro y extiendo los valores de 4 a 8 bytes. Si metiese de parametro a la macro [ebp + ...] terminaria haciendo 
	; doble indireccion en algun momento, asique mejor asi
	mov		edx,	[ebp + 8]
	LevantarNGdeMini		eax,		edx
	cdq
	mov		esi,	eax
	mov		ebx,	edx
	mov		edx,	[ebp + 12]
	LevantarNGdeMini		eax,		edx
	cdq
	mov		ecx,	eax
	
	; Sumo la parte baja de los sumandos y la alta con carry, por si la suma de los bajos tiro un carry
	add		esi,	ecx
	adc		ebx,	edx
	
	; Creo el NGde de retorno (siempre de tamaño 8) y guardo el puntero en ecx
	NuevoNGde		8
	
	; Agrego las dos mitades del resultado
	mov		dword		[edi + 4],		esi
	mov		dword		[edi],			ebx
	
	SF_fin
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	NGde* RestaNxDI(NGde *minuendo, NGde *sustraendo)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RestaNxDI:
	SF_ini
	
	mov		ebx,		[ebp + 8]		; ebx -> minuendo
		
	; Creo el retorno con 4 bytes mas que el minuendo
	mov		esi,		[ebx]			; esi -> minuendo.tam
	add		esi,		4
	NuevoNGde			esi				; eax -> ret, edi = ret.r
		
	push 	eax							; Guardo el valor de retorno asi ahora lo puedo pisotear felizmente
	mov		ecx,		[ebx]			; recupero el minuendo.tam en ecx
	
	; Cargo el valor del sustraendo, total es de 4 bytes
	mov		esi,		[ebp + 12]		; esi -> sustraendo
	mov		edx,		[esi + 4]		; edx = sustraendo.r
	mov		edx,		[edx]			; edx = *(sustraendo.r)
	
	; Le resto el sustraendo al dword menos significativo del minuendo y ya voy guardando en ret
	mov		eax,		[ebx + 4]		; eax -> minuendo.r
	mov		esi,		[eax + ecx - 4]	; esi = LSdword del minuendo.r
	sub		esi,		edx				; esi = la resta de los dwords mas bajos
	mov		dword		[edi + ecx],		esi	; Guardo en el LSdword del ret.r, a este no le resto 4 porque tiene 4 bytes mas que el minuendo
	
	; Ahora voy a ir recorriendo todos los dwords restando los burrows que se pudieron haber formado
	; hasta que no tenga carry o me quede sin mas minuendo
	_bucle_burrow:
		dec		ecx									; Hago esta chanchada para no alterar el carry
		dec		ecx
		dec		ecx
		dec		ecx
		jz		_fin_bucle_burrow					; Si no tengo mas tamaño a quien pedirle, termine. En algun momento va a ser 0 porque minuendo.tam mod 4 = 0 y voy restando de a 4

		mov		esi,		[eax + ecx - 4]			; Cargo el dword del minuendo.r
		sbb		esi,		0						; Le resto solo el posible burrow (o carry)
		mov		dword		[edi + ecx],		esi	; Escribo en el ret.r
		
		jmp		_bucle_burrow
	_fin_bucle_burrow:
	
	; Por ultimo, tengo que decidir si los 4 bytes de sobra que tiene el ret son extendidos de positivo o negativo.
	cmp			dword		esi,		0
	jl			_neg
		_pos:
			mov			dword		[edi],		0x00000000
			jmp			_sig
		_neg:
			mov			dword		[edi],		0xFFFFFFFF
	_sig:
		
	pop		eax										; Recupero el puntero al ret que habia pisoteado felizmente
		
	SF_fin
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Codigo en C para probar las funciones

#include <stdio.h>
#include <stdlib.h>

/* Hice que la estructura sea un tipo asi mejoraba la sintaxis, en el fondo son lo mismo */
typedef struct{int tam; int *r;} NGde;

/* Le juramos a C que vamos a definirle estas funciones afuera */
extern NGde* SumaMiniI(NGde *sumando1, NGde *sumando2);
extern NGde* RestaNxDI(NGde *minuendo, NGde *sustraendo);


/* Muestra un NGde por pantalla */
void MostrarNGde(const NGde n)
{
	/* Notar que como r es puntero a int hay que sumar solo 1 para avanzar un dword (sizeof(int) == 4) */
	int i = 0;
	while(i < n.tam)
	{
		printf("%p ", *(n.r + i / 4));
		i = i + 4;
	}
}


/************* Rutina de pruebas de la primer funcion *************/
void PruebasSumaMiniI()
{
	/* Declaro 4 NGdes para usar de ejemplo y 3 punteros que van a apuntar a sus sumas */
	NGde a;
	NGde b;
	NGde c;
	NGde d;
	NGde e;
	NGde *s1;
	NGde *s2;
	NGde *s3;
	
	/* Inicializo los 4 NGdes con algunos valores */
	a.tam = 4;
	a.r = malloc(a.tam);
	*(a.r) = 0xFFFFFFFF;
	printf("a.tam: %u, *(a.r): ", a.tam);
	MostrarNGde(a);
	printf("\n");
	
	b.tam = 1;
	b.r = malloc(b.tam);
	*(b.r) = 0x0B;
	printf("b.tam: %u, *(b.r): ", b.tam);
	MostrarNGde(b);
	printf("\n");
	
	c.tam = 2;
	c.r = malloc(c.tam);
	*(c.r) = 0x4513;
	printf("c.tam: %u, *(c.r): ", c.tam);
	MostrarNGde(c);
	printf("\n");
	
	d.tam = 2;
	d.r = malloc(d.tam);
	*(d.r) = 0xE320;
	printf("d.tam: %u, *(d.r): ", d.tam);
	MostrarNGde(d);
	printf("\n");
	
	e.tam = 4;
	e.r = malloc(e.tam);
	*(e.r) = 0xFFFFFFFF;
	printf("e.tam: %u, *(e.r): ", e.tam);
	MostrarNGde(e);
	printf("\n");
	
	
	/* Tres sumas de ejemplo */
	s1 = SumaMiniI(&a, &b);
	printf("s1->tam: %u, *(s1->r): ", s1->tam);
	MostrarNGde(*s1);
	printf("\n");
	
	s2 = SumaMiniI(&c, &d);
	printf("s2->tam: %u, *(s2->r): ", s2->tam);
	MostrarNGde(*s2);
	printf("\n");
	
	s3 = SumaMiniI(&e, &a);
	printf("s3->tam: %u, *(s3->r): ", s3->tam);
	MostrarNGde(*s3);
	printf("\n");
	
	
	/* Los leaks son mala onda */
	free(s1->r);	free(s2->r);	free(s1);	free(s2);
}


/************* Rutina de pruebas de la segunda funcion *************/
void PruebasRestaNxDI()
{
	/* Declaro 4 NGdes para usar de ejemplo y 3 punteros que van a apuntar a sus restas */
	NGde a;
	NGde b;
	NGde c;
	NGde d;
	NGde *r1;
	NGde *r2;
	NGde *r3;
	
	/* Inicializo los 4 NGdes con algunos valores */
	a.tam = 4;
	a.r = malloc(a.tam);
	*(a.r) = 0x00000100;
	printf("a.tam: %u, *(a.r): ", a.tam);
	MostrarNGde(a);
	printf("\n");
	
	b.tam = 4;
	b.r = malloc(b.tam);
	*(b.r) = 0x0000000A;
	printf("b.tam: %u, *(b.r): ", b.tam);
	MostrarNGde(b);
	printf("\n");
	
	c.tam = 12;
	c.r = malloc(c.tam);
	*(c.r) = 0xAE3490F1;
	*(c.r + 1) = 0xAE3490F1;
	*(c.r + 2) = 0xAE3490F1;
	printf("c.tam: %u, *(c.r): ", c.tam);
	MostrarNGde(c);
	printf("\n");
	
	d.tam = 32;
	d.r = malloc(d.tam);
	*(d.r) = 0;
	*(d.r + 1) = 0;
	*(d.r + 2) = 0;
	*(d.r + 3) = 0;
	*(d.r + 4) = 0;
	*(d.r + 5) = 0;
	*(d.r + 6) = 0;
	*(d.r + 7) = 0;
	printf("d.tam: %u, *(d.r): ", d.tam);
	MostrarNGde(d);
	printf("\n");
	
	/* Tres restas de ejemplo */
	r1 = RestaNxDI(&b, &a);
	printf("r1->tam: %u, *(r1->r): ", r1->tam);
	MostrarNGde(*r1);
	printf("\n");
	
	r2 = RestaNxDI(&c, &a);
	printf("r2->tam: %u, *(r2->r): ", r2->tam);
	MostrarNGde(*r2);
	printf("\n");
	
	r3 = RestaNxDI(&d, &a);
	printf("r3->tam: %u, *(r3->r): ", r3->tam);
	MostrarNGde(*r3);
	printf("\n");
	
	
	/* Los leaks son mala onda */
	free(r1->r);	free(r2->r);	free(r3->r);	free(r1);	free(r2);	free(r3);
}


/************* Punto de entrada ****************/
int main(int argc, char *argv[])
{
	printf(" .................. Pruebas de SumaMiniI .................. \n");
	PruebasSumaMiniI();
	printf("\n\n .................. Pruebas de RestaNxDI .................. \n");
	PruebasRestaNxDI();
	
	return 0;
}


Makefile para compilar los dos archivos

RM= rm
NASM = nasm

# optimization
#
OPT= -g -ggdb -O2

# flags for ANSI compiles
#
CFLAGS= -pedantic -ansi -Wall ${OPT}

# ANSI compiler
#
GCC= gcc

OBJ=main.o parcial.o
OTHEROBJ=
INCS=
MAIN=parcial

.PHONY: all win linux

all: 
	@echo Debe elegir alguno de los sistemas operativos \(win, linux\). Ejemplo:
	@echo   make linux

win:
	make NOPT="-fwin32 -Dwin32"  ${MAIN}

linux:
	make NOPT=-felf ${MAIN}

${MAIN}: ${OBJ} ${OTHEROBJ} $(INCS)
	${GCC} ${CFLAGS} -o ${MAIN} ${OBJ} ${OTHEROBJ}

%.o: %.asm 
	${NASM} ${NOPT} -O1 $< -o $@

%.o: %.c
	${GCC} ${CFLAGS} -c $< -o [email protected] 

clean:
	${RM} -f ${OBJ} ${OTHEROBJ} ${MAIN}

install: all
	${CAT} ${MAIN} > /dev/null

Notar que solo hay que poner "make win" o "make linux".


Ejercicio 2 (IA64)[editar]

a) signo

.proc signo
signo:
   alloc loc0 = ar.pfs,1,1,0,0
   
   cmp.eq p1,p2 = 0, in0
   (p1) mov r8 = 0
   (p2) cmp.gts.unc p3, p4 = 0, in0
   (p3) mov r8 = -1
   (p4) mov r8 = 1
   mov ar.pfs = loc0
   br.ret.sptk.many b0
.endp signo

b) Listas

.proc listas
listas:
    alloc loc0 = ar.pfs,5,3,1,0
    mov ar.lc = in4 // in4=N
    mov loc1 = b0 //guarda el branch
loop:
    ld8 loc2 = [in0], 8
    mov out0 = loc2
    br.call b0 = signo
    cmp.eq p1,p2 = 0, r8
    (p1) st8 [in3] = loc2, 8 // in3 = ceros
    (p2) cmp.gts.unc p3, p4 = 0, r8
    (p3) st8 [in2] = loc2, 8 // negativos
    (p4) st8 [in1] = loc2, 8 // positivos
    br.cloop loop
    
    st8 [in1] = r0
    st8 [in2] = r0
    st8 [in3] = -1
    
    mov b0 = loc1
    mov ar.pfs = loc0
    br.ret.sptk.many bo  //termina la locura


Para Patricia esto estaba bien, espero que lo este para uds.