Estructura de Computadores 4.- Programación en Ensamblador Parte IV
Contenido Subrutinas. Llamadas al sistema. Página 2
Subrutinas Módulos de programa que pueden reutilizarse en distintos puntos del programa. Equivalen a procedimientos y funciones pero a bajo nivel. Pueden tomar parámetros y devolver resultados. Página 3
Pasos del programa Situar los parámetros en un lugar donde el procedimiento puede acceder a los mismos. Transferir el control al procedimiento. Adquirir los recursos de almacenamiento necesarios. Realizar la tarea. Situar el valor de resultado en un lugar donde el programa pueda accederlo. Retornar el control al punto de origen. Página 4
Subrutinas - Parámetros Cuatro registros disponibles para paso de parámetros $a0, $a1, $a2, $a3 Si se necesitan pasar más parámetros se debe hacer mediante la pila. El programa llamante coloca los parámetros en la pila. La subrutina llamada recupera los parámetros de la pila. Página 5
Subrutinas Transferencia de Control jal etiqueta Instrucción. Jump and link. Salta incondicionalmente a la instrucción objetivo. Salva la dirección de la instrucción siguiente en el registro 31 ($ra). jalr $reg1, $reg2 Instrucción. Jump and link register. Salta incondicionalmente a la instrucción cuya dirección es $reg1. Salva la dirección de la instrucción siguiente en el registro $reg2. Página 6
Subrutinas Reserva de espacio Las variables locales a una subrutina se almacenan en la pila. Se reserva espacio en la pila incrementando el puntero de pila. Solamente se reserva espacio en la pila si no se tiene suficiente con los registros o si se trata de tablas o estructuras. Página 7
Subrutinas Bloque de activación Bloque de memoria de la pila formado por: Registros de parámetros salvados. Dirección de retorno salvada. Registros salvados. Datos locales. Problema: El puntero de pila se puede modificar con lo que es difícil referenciar a los datos del bloque de activación. Solución: Guardar el inicio del bloque de activación en $fp. Página 8
Subrutinas Resultado Dos registros disponibles para el retorno de resultados: $v0, $v1 Si se necesita más espacio se debe utilizar la pila: La subrutina llamada coloca el resultado en la pila. El programa llamante recoge el resultado de la pila. Página 9
Subrutinas Retorno de control jr $ra Instrucción. Jump register. Salta incondicionalmente a la instrucción cuya dirección está en el registro $ra. Observación main es una subrutina. Termina con jr $ra para devolver el control al código de arranque del programa. Página 10
Pasos al entrar en una subrutina Salvar la dirección de retorno. Salvar el valor del puntero de marco de pila. Ajustar el valor del puntero de marco de pila. Guardar los parámetros en la pila. Guardar los registros $s que se utilicen. Reservar espacio local en la pila. Página 11
Pasos al salir de una subrutina Restaurar los valores de los registros $s salvados. Restaurar el puntero de marco de pila. Restaurar el registro de dirección de retorno. Restaurar el puntero de pila. Página 12
Ejemplo: Cálculo no recursivo del factorial void main() { int x = 5; int y; y = factorial(x); } int factorial(int x) { int r = 1; for (int i=1; i<=x; i++) r *= i; return r; } Página 13
Programa principal.data x:.word 5 y:.word 0.text.globl main main: #reserva de la pila sub $sp, $sp, 16 #salvado de $ra sw $ra, ($sp) #salvado de parametros sw $a0, 4($sp) sw $a1, 8($sp) sw $a2, 12($sp) #parametro de factorial lw $a0, x #invocacion jal factorial #almacenamiento de resultado sw $v0, y #restauracion de parametros lw $a0, 4($sp) lw $a1, 8($sp) lw $a2, 12($sp) #restauracion de $ra lw $ra, ($sp) #liberacion de la pila add $sp, $sp, 16 #salida jr $ra Página 14
Subrutina no recursiva factorial: # no se llama a otra función por lo que no # hay que salvar dirección de retorno ni # parametros. # no hay variables locales almacenadas en pila # por lo que no hay que usar $sp li $v0, 1 li $t1, 1 bucle: mul $v0, $v0, $t1 addi $t1, 1 ble $t1, $a0, bucle jr $ra Página 15
Factorial recursivo factorial: # Guarda en la pila $ra y $s0 sub $sp, $sp, 8 sw $ra, ($sp) sw $s0, 4($sp) #si $a0<=0 -> else ble $a0, 0, else #parte then move $s0, $a0 sub $a0, $a0, 1 jal factorial mul $v0, $v0, $s0 b salida #parte else else: li $v0, 1 salida: #Restaura $ra y $s0 lw $s0, 4($sp) lw $ra, ($sp) add $sp, $sp,8 jr $ra Página 16
Llamadas al sistema SPIM ofrece un conjunto de llamadas al sistema operativo mediante la instrucción syscall. Utilidades: Impresión en la consola. Lectura de la consola. Reserva de memoria. Terminación de un programa. Página 17
Llamadas al sistema: Formato Cada servicio tiene asignado un código de llamada al sistema. El código de servicio se carga en $v0. Cada llamada al sistema puede tomar uno o más parámetros. Los parámetros se cargan en $a0-$a3y $f12. Algunas llamadas pueden devolver valores. Los resultados se dejan en $v0 o $f0. Página 18
Salida print_int Código 1 Parámetro $a0 print_double Código 3 Parámetro $f12 print_float Código 2 Parámetro $f12 print_string Código 4 Parámetro $a0 Página 19
Entrada read_int Código 5 Resultado $v0 read_double Código 7 Resultado $f0 read_float Código 6 Resultado $f0 read_string Código 8 Parámetros: $a0 buffer $a1 longitud Página 20
Otras sbrk exit Código 9 Devuelve un puntero aun bloque de memoria que contiene n bytes. $a0 número de bytes a reservar. $v0 dirección de comienzo del bloque. Código 10 Página 21
Actividad Escriba un programa que calcule los n primeros números primos. Utilice una función es_primo(k) que devuelva 1 si k es primo y 0 si no es primo. El programa principal itera hasta que ha escrito en la consola n números primos. Página 22
Actividad Escriba una subrutina que tome como parámetros tres números de 64 bits y devuelva el producto de los mismos como un número de 128 bits. Página 23