3. Traduciendo y ejecutando un programa Programa C Programa en lenguaje ensamblador Cód. Objeto: módulo en lenguaje de máquina Cod. Objeto: Bibliotecas Cod. Ejecutable: Prog. Leng. Máquina Memoria Compilador Ensamblador Linker Loader
13. Convención de uso de registros MIPS $0 zero constante cero $1 at reservado para ensamblador $2 v0 evaluación de expresiones y $3 v1 resultados de funciones $4 a0 argumentos a funciones $5 a1 $6 a2 $7 a3 $8 t0 variables temporales respaldadas por función . que invoca . (función invocada puede . sobreescribir) $15 t7 $16 s0 temporales respaldados por . función invocada . (función que invoca no respalda) . $23 s7 $24 t8 temporales (adicionales) $25 t9 $26 k0 reservados para sistema operativo $27 k1 $28 gp puntero a variables globales $29 sp puntero a tope del stack $30 fp puntero a base del stack $31 ra dirección de retorno de función
27. Algunas pseudoinstrucciones move $4, $5 # $4 $5 # or $4, $zero, $5 li $4, 100 # $4 100 # ori $4, $zero, 100 la $4, LABEL32 # $4 LABEL # lui $4, LABEL 16bsuperiores # ori $4, $4, LABEL 16binferiores bgt $4, CTE, LABEL # if ($4 > CTE) goto LABEL # slti $at, $4, CTE+1 # beq $at, $zero, LABEL
28. Ejemplo int a, b, acum; … acum = acum + a * b; # Dirección de memoria de ‘a’ en rótulo DIR_A # Dirección de memoria de ‘b’ en rótulo DIR_B # Dirección de memoria ‘acum’ en rótulo DIR_ACUM la $v0, DIR_A # cargar dirección de a la $v1, DIR_B # cargar dirección de b lw $t0, 0($v0) # leer a lw $t1, 0($v1) # leer b mul $t2, $t0, $t1 # t2 = a * b la $v2, DIR_ACUM # cargar dirección de acum lw $t3, 0($v2) # leer acum add $t3, $t3, $t2 # $t3 = acum + a * b sw $t3, 0($v2) # guardar acum 10 2 DIR_A DIR_B DIR_ACUM 50 Memoria $v0 $v1 $v2 $t0 $t1 $t2 $t3 1000 1012 10 2 20 1024 50 70 70 1000 1004 1008 1012 1016 1020 1024 a b acum
29. Ejemplo typedef struct { int x; int y; } coord; coord c1, c2; … int dist; dist = abs(c2.x – c1.x) + abs(c2.y – c1.y); # Dirección de memoria de ‘c1’ en rótulo DIR_C1 # Dirección de memoria de ‘c2’ en rótulo DIR_C2 # Dirección de memoria de ‘dist’ en rótulo DIR_DIST la $v0, DIR_C1 # cargar dirección de c1 la $v1, DIR_C2 # cargar dirección de c2 lw $t0, 0($v0) # leer c1.x lw $t1, 0($v1) # leer c2.x sub $t2, $t1, $t0 # t2 = c2.x – c1.x abs $t3, $t2 # t3 = abs(c2.x – c1.x) lw $t0, 4($v0) # leer c1.y lw $t1, 4($v1) # leer c2.y sub $t2, $t1, $t0 # t2 = c2.y – c1.y abs $t4, $t2 # t4 = abs(c2.y – c1.y) add $t3, $t3, $t4 # t3 = abs(c2.x – c1.x) + # abs(c2.y – c1.y) la $v0, DIR_DIST # cargar dirección de dist sw $t3, 0($v0) # dist = abs(c2.x – c1.x) + # abs(c2.y – c1.y) c1.x c1.y c2.x c2.y Direcciones de memoria DIR_C1 DIR_C1 + 4 DIR_C2 DIR_C2 + 4 DIR_DIST dist Memoria
30.
31.
32.
33.
34.
35.
36.
37. Ejemplo Código assembly para el siguiente código C: int a = 10, b = 5; int c; … if (a > b) c = a – b; else c = b – a; c = c + 10; Compilador asigna: a $t0 b $t1 c $t2 li $t0, 10 # a = 10 li $t1, 5 # b = 5 sle $t3, $t0, $t1 # a <= b ? bgtz $t3, ELSE # if a <= b goto ELSE sub $t2, $t0, $t1 # c = a - b j FIN_IF # goto FIN_IF ELSE: sub $t2, $t1, $t0 # c = b - a FIN_IF: addi $t2, $t2, 10 # c = c + 10
38. Ejemplo Código assembly para el siguiente código C: i = 0; sum = 0; do { sum = sum + a[i] * b[i]; i++; } while (i < 100) li $t0, 0 # i = 0; li $t1, 0 # $t1 = 0 (sum temporal) la $t2, SUM # $t2 = dirección de sum sw $t1, 0($t2) # sum = 0 LOOP: la $t3, A # $t3 = dirección a[0] la $t4, B # $t4 = dirección b[0] sll $t5, $t0, 2 # $t5 = i*4 add $t6, $t3, $t5 # $t6 = dirección a[i] lw $t7, 0($t6) # $t7 = a[i] add $t6, $t4, $t5 # $t6 = dirección b[i] lw $t8, 0($t6) # $t8 = b[i] mul, $t8, $t7, $t8 # $t8 = a[i]*b[i] add $t1, $t1, $t8 # $t1 = sum + a[i]*b[i] la $t2, SUM sw, $t1, 0($t2) # sum = sum + a[i] * b[i] add $t0, $t0, 1 # i = i + 1 slti $t7, $t0, 100 # i < 100? bne $t7, $zero, LOOP Vectores a y b y variable sum comienzan a partir de direcciones de memoria indicadas por rótulos A, B y SUM. Variable i asignada a registro $t0. ¿Posible optimizar código?
39. Ejemplo (optimizado) Código assembly para el siguiente código C: i = 0; sum = 0; do { sum = sum + a[i] * b[i]; i++; } while (i < 100) li $t0, 0 # i = 0; li $t1, 0 # $t1 = 0 (sum temporal) la $t3, A # $t3 = dirección a[0] la $t4, B # $t4 = dirección b[0] LOOP: add $t6, $t3, $t0 # $t6 = dirección a[i] lw $t7, 0($t6) # $t7 = a[i] add $t6, $t4, $t0 # $t6 = dirección b[i] lw $t8, 0($t6) # $t8 = b[i] mul, $t8, $t7, $t8 # $t8 = a[i]*b[i] add $t1, $t1, $t8 # $t1 = sum + a[i]*b[i] add $t0, $t0, 4 # i = i + 1 slti $t7, $t0, 400 # i < 100? bne $t7, $zero, LOOP la $t2, SUM sw, $t1, 0($t2) # sum = sum + a[i] * b[i] Vectores a y b y variable sum comienzan a partir de direcciones de memoria indicadas por rótulos A, B y SUM. Variable i asignada a registro $t0.
45. Algunas directivas al ensamblador .data Texto que sigue representa datos almacenados en el heap .text Texto que sigue representa instrucciones almacenadas en área de texto (código) .kdata Texto que sigue representa datos en área de datos del kernel (sistema operativo) .ktext Texto que sigue representa código en área de kernel .globl LABEL Rótulo LABEL es global (visible a todo el programa) .ascii str Almacenar string de texto str en ASCII sin un NULL al final .asciiz str Almacenar string de texto str en ASCII con un NULL (0) al final .word w1 … wn Almacenar n palabras (32b) en posiciones consecutivas de memoria .half h1 … hn Almacenar n medias palabras (16b) en posiciones consecutivas de memoria .byte b1 … bn Almacenar n bytes (8b) en posiciones consecutivas de memoria
46. Ejemplo .data TEXTOSINULL: .ascii “texto 1” TEXTOCONUL: .asciiz “texto 2” DATOS: .word 16 124 1000 .text .globl MAIN MAIN: la $8, TEXTOSINUL la $9, TEXTOCONUL la $10, DATOS lw $11, 0($10) lw $12, 4($10) lw $13, 8($10)
47.
48.
49. Ejemplo procedimiento simple int len; char[20] str; … len = strlen(str); … int strlen(char *str) { int len = 0; while (*str != 0) { str = str + 1; len = len + 1; } return len; } la $a0, str # $a0 = str jal STRLEN; # resultado retorna en $v0 STRLEN: li $v0, 0 # len = 0 WHILE: lb $t0, 0($a0) # $t0 = *str beq $t0, $zero, FIN_WHILE # if (*str == 0) goto FIN_W addi $a0, $a0, 1 # str = str + 1 addi $v0, $v0, 1 # len = len + 1 b WHILE # goto WHILE FIN_W: jr $ra # return len Utilizar convención estándar de uso de registros MIPS
50. Otro ejemplo procedimiento int i; int a[100], b[100] … res = punto(a, b, 100); … int prod_punto(int v1[], int v2[], int n) { int i = 0; suma = 0; do { suma = suma + v1[i] * v2[i]; i++; } while (i < n) return suma; } la $a0, A # $a0 = &(a[0]) la $a1, B # $a1 = &(b[0]) li $a2, 100 # $a2 = 100 jal PUNTO # resultado en $v0 la $t0, RES sw $v0, 0($t0) … PUNTO: li $t0, 0 # i = 0 li $v0, 0 # suma = 0 WHILE: sll $t1, $t0, 2 # $t1 = i*4 add $t2, $a0, $t1 # $t2 = &(v1[i]) lw $t3, 0($t2) # $t3 = v1[i] add $t2, $a1, $t1 # $t2 = &(v2[i]) lw $t4, 0($t2) # $t4 = v2[i] mult $t3, $t3, $t4 # $t3 = v1[i] * v2[i] add $v0, $v0, $t3 # suma = suma +… addi $t0, $t0, 1 # i = i + 1 slt $t3, $t0, $a2 # i < n? bne $t3, $zero, WHILE jr $ra
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73. Convención uso de registros Dirección de retorno de función $ra $31 Puntero a la base del stack (Frame Pointer) $fp $30 Puntero al tope del stack (Stack Pointer) $sp $29 Puntero al heap (segmento datos global) $gp $28 Reservados al O.S. $k0-$k1 $26-$27 Temporales no salvados al llamar función $t8-$t9 $24-$25 Temporales salvados al llamar función $s0-$s7 $16-$23 Temporales no salvados al llamar función $t0-$t7 $8-$15 Argumentos en llamada función $a0-$a3 $4-$7 Evaluación expresiones y resultado funciones $v0-$v1 $2-$3 Reservado para temporal del ensamblador $at $1 Cero $zero $0 Uso Nombre Registro
74.
75.
76.
77.
78. Ejemplo: Factorial recursivo int factorial(int n) { if (n == 0) return 1; else return n * factorial(n-1); } FACT: bne $a0, $0, L1 # saltar si n != 0 li $v0, 1 # retornar 1 jr $ra L1: addiu $sp, $sp, -12 # tamaño del nuevo stack es 12 bytes sw $fp, 0($sp) # almacenar $fp en el stack sw $ra, 4($sp) # almacenar $ra en el stack addiu $fp, $sp, 8 # $fp apunta al principio del stack sw $a0, 0($fp) # almacenar n en el stack addiu $a0, $a0, -1 # n - 1 jal FACT # resultado en $v0 lw $a0, 0($fp) # recuperar n lw $ra, 4($sp) # recuperar direccion de retorno lw $fp, 0($sp) # recuperar $fp addiu $sp, $sp, 12 # restaurar stack original $sp mul $v0, $v0, $a0 # n * fact(n-1) jr $ra Mostrar ejemplos usando fp y no usando fp, usando ConTEXT Ejercicio: hacer dibujo con marcos de activación y cadena de llamados