jueves, 23 de febrero de 2012

[CÓMPUTO INTEGRADO] Tarea intro

Mi programa trata de hacer una simple matriz de 5 por 5.

Primero que nada, mi intención era mostrar el código generado por Mac OS X, sin embargo es un poco complicado ya que muestra demaciadas lineas a comparación de las que genera Ubuntu 10.10, mostrare a modo de ejemplo ambos códigos generados y pasare a explicar el código modificado de Ubuntu.

Éste es el código en C. Los números se generan de manera aleatoria.

#include (stdio.h)

int main(void){
  srand(time(0));
  int i = 0, j = 0;
  int matriz[5][5];
  for (i = 0; i <= 5; i++){
    for (j = 0; j<=5; j++){
      matriz[i][j]=(rand () %9)+1;
    }
  }
  for (i = 0; i <= 5; i++){
    for (j = 0; j<=5; j++){
      printf("%d",matriz[i][j]);
    }
    printf("\n");
  }
 
  return 0;
}
Éste es el código ensamblador autogenerado del archivo anterior con el comando "gcc -S archivo.c" de Ubuntu.
.file "matriz.c"                      # Nombre del archivo
.section .rodata                 #

.LC0:                                   # Etiqueta para el string
.string "%d "                           # El string

.text                                   # Inicio
.globl main                             # Indica que main es global
.type main, @function                 # Indica que main es una función

main:                                   # Inicio de main
 pushl %ebp                            # Se coloca ebp al inicio
 movl %esp, %ebp                      # Se mueve esp a ebp
 andl $-16, %esp                      # Operación lógica entre esp y -16
 pushl %esi                            # Registro esi
 pushl %ebx                            # Registor ebx
 subl $136, %esp                      # Se reserva espacio en esp
 movl $0, (%esp)                      # Se asigna la dirección 0 a esp
 call time                            # Se llama a time de la librería estandar
 movl %eax, (%esp)                    # Se mueve eax a esp
 call srand                           # Se llama a srand de la librería estandar
 movl $0, 124(%esp)                   # Se asigna la dirección 0 a la posición 124 de esp
 movl $0, 120(%esp)                   # Se asigna la dirección 0 a la posición 120 de esp
 movl $0, 124(%esp)                   # Se asigna la dirección 0 a la posición 124 de esp
 jmp .L2                             # Se salta a la sección L2

.L5:                                    # Sección L5
 movl $0, 120(%esp)                   # Se mueve la dirección 0 a la posición 120 dde esp
 jmp .L3                             # Salta a L3

.L4:                                    # Sección L4
movl 124(%esp), %ebx                 # Se mueve el valor de la posición 124 de esp a ebx
movl 120(%esp), %esi                 # Se mueve el valor de la posición 120 de esp a esi
call rand                            # Se llama a rand de la librería estandar
movl %eax, %ecx                      # Se mueve eax a ecx
movl $954437177, %edx                # Se asigna la dirección 954437177 a edx 
movl %ecx, %eax                      # Se mueve ecx a eax
imull %edx                            # Se multiplica edx por 1
sarl %edx                            # Se desplaza 1 posición a la derecha en edx
movl %ecx, %eax                      # Se mueve ecx a eax
sarl $31, %eax                       # Se desplaza 31 posiciones a la derecha en eax
subl %eax, %edx                      # Se resta eax a edx
movl %edx, %eax                      # se mueve edx a eax
sall $3, %eax                        # Se desplaza 3 posiciones a la izquierda en eax
addl %edx, %eax                      # Se agrega edx a eax
movl %ecx, %edx                      # Se mueve ecx a edx
subl %eax, %edx                      # Se resta eax a ecx
addl $1, %edx                        # Se agrega 1 a edx
movl %ebx, %eax                      # Se mueve ebx a eax
sall $2, %eax                        # Se desplaza dos posiciones a la izquierda en eax
addl %ebx, %eax                      # Se agrega ebx a eax
addl %esi, %eax                      # Se agrega esi a eax
movl %edx, 20(%esp,%eax,4)           #########
addl $1, 120(%esp)                   # Se agrega 1 al valor de la posición 120 de esp

.L3:                                    # Sección L3
cmpl $5, 120(%esp)                   # Comparación entre 5 y el valor de la posición 120 de esp
jle .L4                             # Salta a L4 si la comparación anterior es menor o igual al valor de esp
addl $1, 124(%esp)                   # Se agrega 1 al valor de la posición 124 de esp

.L2:                                    # Sección L2
cmpl $5, 124(%esp)                   # Comparación entre 5 y el valor de la posición 124 de esp
jle .L5                             # Salta a L5 si la comparación anterior es menor o igual al valor de esp
movl $0, 124(%esp)                   # Se asigna la dirección 0 a la posición 124 de esp
jmp .L6                             # Se salta a la sección L6

.L9:                                    # Sección L9
movl $0, 120(%esp)                   # Se asigna la dirección 0 a la posición 120 de esp
jmp .L7                             # Salta a la sección L7

.L8                                     # Sección L8
movl 124(%esp), %edx                 # Se asigna el valor de la posición 124 de esp a edx
movl 120(%esp), %ecx                 # Se asigna el valor de la posición 120 de esp a ecx
movl %edx, %eax                      # Se mueve edx a ecx
sall $2, %eax                        # Se desplaza dos posiciones a la izquierda en eax
addl %edx, %eax                      # Se agrega el valor de edx a eax
addl %ecx, %eax                      # Se agrega el valor de ecx a eax
movl 20(%esp,%eax,4), %edx           #########
movl $.LC0, %eax                     # Se asigna el string LC0 a eax
movl %edx, 4(%esp)                   # Se mueve edx a la posición 4 de esp
movl %eax, (%esp)                    # Se mueve eax a el principio de esp
call printf                          # Se llama a printf de la librería estandar
addl $1, 120(%esp)                   # Se agrega 1 a la posición 120 de esp

.L7:                                    # Sección L7
cmpl $5, 120(%esp)                   # Comparación entre 5 y el valor de la posición 120de esp
jle .L8                             # Salta a L8 si la comparación anterior es menor o igual al valor de esp
movl $10, (%esp)                     # Se asigna 10 al inicio de esp
call putchar                         # Se llama a putchar de la librería estandar
addl $1, 124(%esp)                   # Se agrega 1 a la posición 124 de esp

.L6:                                    # Sección L6
cmpl $5, 124(%esp)                   # Comparación entre 5 y el valor de la posición 124 de esp
jle .L9                             # Salta a L9 si la comparación anterior es menor o igual al valor de esp
movl $0, %eax                        # Se asigna el valor 0 a eax
addl $136, %esp                      # Se agrega 136 a esp
popl %ebx                            # Sale ebx
popl %esi                            # Sale esi
movl %ebp, %esp                      # Se mueve ebp a esp
popl %ebp                            # Sale ebp
ret                                     # Return, fin del programa

.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits

Este es el código generado por Mac OS X
 .section __TEXT,__text,regular,pure_instructions
 .globl _main
 .align 4, 0x90
_main:
Leh_func_begin1:
 pushq %rbp
Ltmp0:
 movq %rsp, %rbp
Ltmp1:
 subq $128, %rsp
Ltmp2:
 xorl %eax, %eax
 xorb %cl, %cl
 movl %eax, %edi
 movb %cl, %al
 callq _time
 movl %eax, %ecx
 xorb %dl, %dl
 movl %ecx, %edi
 movb %dl, %al
 callq _srand
 movl $0, -12(%rbp)
 movl $0, -16(%rbp)
 movl $0, -12(%rbp)
 jmp LBB1_5
LBB1_1:
 movl $0, -16(%rbp)
 jmp LBB1_3
LBB1_2:
 movl -12(%rbp), %eax
 movl -16(%rbp), %ecx
 xorb %dl, %dl
 movl %eax, -120(%rbp)
 movb %dl, %al
 movl %ecx, -124(%rbp)
 callq _rand
 movl %eax, %ecx
 movl $954437177, %esi
 movl %ecx, %eax
 imull %esi
 movl %edx, %eax
 movl %eax, %esi
 shrl $31, %esi
 sarl %eax
 leal (%rax,%rsi), %eax
 movl %eax, %esi
 leal (%rax,%rsi,8), %eax
 negl %eax
 leal 1(%rcx,%rax), %eax
 movl -120(%rbp), %ecx
 movslq %ecx, %rcx
 movq %rcx, %rsi
 leaq (%rcx,%rsi,4), %rcx
 leaq -116(%rbp,%rcx,4), %rcx
 movl -124(%rbp), %esi
 movslq %esi, %rsi
 movl %eax, (%rcx,%rsi,4)
 movl -16(%rbp), %eax
 leal 1(%rax), %eax
 movl %eax, -16(%rbp)
LBB1_3:
 movl -16(%rbp), %eax
 cmpl $5, %eax
 jle LBB1_2
 movl -12(%rbp), %eax
 addl $1, %eax
 movl %eax, -12(%rbp)
LBB1_5:
 movl -12(%rbp), %eax
 cmpl $5, %eax
 jle LBB1_1
 movl $0, -12(%rbp)
 jmp LBB1_11
LBB1_7:
 movl $0, -16(%rbp)
 jmp LBB1_9
LBB1_8:
 movl -12(%rbp), %eax
 movl -16(%rbp), %ecx
 movslq %eax, %rax
 leaq -116(%rbp), %rdx
 movabsq $20, %rsi
 imulq %rsi, %rax
 addq %rax, %rdx
 movslq %ecx, %rax
 movl (%rdx,%rax,4), %eax
 xorb %cl, %cl
 leaq L_.str(%rip), %rdx
 movq %rdx, %rdi
 movl %eax, %esi
 movb %cl, %al
 callq _printf
 movl -16(%rbp), %eax
 addl $1, %eax
 movl %eax, -16(%rbp)
LBB1_9:
 movl -16(%rbp), %eax
 cmpl $5, %eax
 jle LBB1_8
 movl $10, %eax
 movl %eax, %edi
 callq _putchar
 movl -12(%rbp), %eax
 addl $1, %eax
 movl %eax, -12(%rbp)
LBB1_11:
 movl -12(%rbp), %eax
 cmpl $5, %eax
 jle LBB1_7
 movl $0, -8(%rbp)
 movl -8(%rbp), %eax
 movl %eax, -4(%rbp)
 movl -4(%rbp), %eax
 addq $128, %rsp
 popq %rbp
 ret
Leh_func_end1:

 .section __TEXT,__cstring,cstring_literals
L_.str:
 .asciz  "%d "

 .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame0:
Lsection_eh_frame:
Leh_frame_common:
Lset0 = Leh_frame_common_end-Leh_frame_common_begin
 .long Lset0
Leh_frame_common_begin:
 .long 0
 .byte 1
 .asciz  "zR"
 .byte 1
 .byte 120
 .byte 16
 .byte 1
 .byte 16
 .byte 12
 .byte 7
 .byte 8
 .byte 144
 .byte 1
 .align 3
Leh_frame_common_end:
 .globl _main.eh
_main.eh:
Lset1 = Leh_frame_end1-Leh_frame_begin1
 .long Lset1
Leh_frame_begin1:
Lset2 = Leh_frame_begin1-Leh_frame_common
 .long Lset2
Ltmp3:
 .quad Leh_func_begin1-Ltmp3
Lset3 = Leh_func_end1-Leh_func_begin1
 .quad Lset3
 .byte 0
 .byte 4
Lset4 = Ltmp0-Leh_func_begin1
 .long Lset4
 .byte 14
 .byte 16
 .byte 134
 .byte 2
 .byte 4
Lset5 = Ltmp1-Ltmp0
 .long Lset5
 .byte 13
 .byte 6
 .align 3
Leh_frame_end1:


.subsections_via_symbols
Ambos códigos tienen una sintaxis parecida, ya que en ambos utilicé una versión de gcc para el sistema. Pero en Ubuntu me lanza menos lineas de código y me es más comprensible, mientras que en OS X lanza demasiadas lineas de debug mezcladas con el código principal.

Ahora, analizaremos cada sección del programa, gcc me dividió el código en 9 secciones. La sección del main define principalmente los registros que se utilizaran durante la ejecución, aparte ejecuta funciones estandar llamadas en el código.

main:
main:
 pushl %ebp      
 movl %esp, %ebp 
 andl $-16, %esp
 pushl %esi      
 pushl %ebx    
 subl $136, %esp 
 movl $0, (%esp) 
 call time       
 movl %eax, (%esp)
 call srand       
 movl $0, 124(%esp)
 movl $0, 120(%esp)
 movl $0, 124(%esp)
 jmp .L2          
Esta parte del código se encarga de colocar las variables en el programa, llama a srand y a time para generar un número aleatorio.

L2:
.L2:                                    
 cmpl $5, 124(%esp)                   
 jle .L5                             
 movl $0, 124(%esp)                   
 jmp .L6                             

L2 se encarga de hacer la comparación entre el valor de "esp" y el número 5. ¿Por qué esto? Porque la matriz sera de 5 x 5, se puede decir que L2 es la parte del código donde se comprueba una dimención de la matriz, y se guarda su dirección para saber donde guardar los números generados.

L5:
.L5:
 movl $0, 120(%esp)
 jmp .L3
                        
En L5 solo se guarda un 0 en la posición 120 de "esp" y se salta a L3.

L3:
.L3:
 cmpl $5, 120(%esp)
 jle .L4          
 addl $1, 124(%esp) 

En esta parte se vuelve a hacer una comparación, esta vez para asignar la segunda dimención de la matriz y se guardara en la posición 120 de "esp". Salta a la sección L4. En esta parte se vuelve a hacer una comparación, esta vez para asignar la segunda dimención de la matriz y se guardara en la posición 120 de "esp". Salta a la sección L4.

Como en los casos anteriores ocurren comparaciones, no se saldra de esas secciones hasta que las coparaciones acierten el "jle" que es un if que comprueba que el valor dado sea menor o igual al del parametro dado, por lo que esta parte seria como el "for" que todos conocen.

L4:
.L4:                       
movl 124(%esp), %ebx    
movl 120(%esp), %esi    
call rand               
movl %eax, %ecx         
movl $954437177, %edx    
movl %ecx, %eax         
imull %edx               
sarl %edx               
movl %ecx, %eax         
sarl $31, %eax          
subl %eax, %edx         
movl %edx, %eax         
sall $3, %eax           
addl %edx, %eax           
movl %ecx, %edx           
subl %eax, %edx           
addl $1, %edx             
movl %ebx, %eax           
sall $2, %eax             
addl %ebx, %eax           
addl %esi, %eax           
movl %edx, 20(%esp,%eax,4)
addl $1, 120(%esp)        

Esta parte es donde se asignan los números aleatorios, en "ebx" y en "esi" se trataran los números generados en forma aleatoria, estos se suman en "eax", en "edx" se guarda un número "954437177" que se guarda como un entero y se resta a "eax" para poner el límite de 0 a 9 a la hora de generar los números, "eax" se suma a "ebx" de nuevo y finalmente pasa a la posición 120 de "esp" y se guarda el número generado.

L4 regresa a L3, L3 a L5 y L5 a L2. El número generado se guarda en la posición 124 de "esp", ahora salta a L6.

L6:
.L6:                    
 cmpl $5, 124(%esp)   
 jle .L9             
 movl $0, %eax        
 addl $136, %esp      
 popl %ebx            
 popl %esi            
 movl %ebp, %esp      
 popl %ebp            
 ret                     

En esta sección se vuelve a comprobar la dimención de la matriz, y se salta a L9, los "popl" sacan los registros para finalizar con el "ret".

L9:
.L9:
 movl $0, 120(%esp)   
 jmp .L7             

L9 al igual que L5, solo guarda la dirección en 120 de "esp", pero esta ocación en lugar de guardar el número, se va a imprimir en pantalla. Para eso se pasa a L7.

L7:
.L7:                     
 cmpl $5, 120(%esp)    
 jle .L8              
 movl $10, (%esp)      
 call putchar          
 addl $1, 124(%esp)    

Esta parte del código hace lo mismo que L3, solo que despues de ejecutar L8 imprime el valor en pantalla. Al haber comparaciones en estos casos tambien, sucede lo mismo que paso anteriormente, por lo que esta parte esria el segundo for del programa, este para recorrer la matriz e imprimir cada valor.

L8:
.L8                          
movl 124(%esp), %edx      
movl 120(%esp), %ecx      
movl %edx, %eax           
sall $2, %eax             
addl %edx, %eax           
addl %ecx, %eax           
movl 20(%esp,%eax,4), %edx
movl $.LC0, %eax          
movl %edx, 4(%esp)        
movl %eax, (%esp)         
call printf               
addl $1, 120(%esp)        

Esta es la parte final del programa, donde se imprime número por número, imprime los valores almacenados en "esp" que están almacenados en las posiciones 120 y 124, todo se agrega a "eax" y se le hace apuntar a LC0 para que imprima un "%d" que sera reemplazado por el valor guardado, justo como sucede en lenguaje C. Se llama a printf.

L8 regresa a L7, L7 a L9 y L9 a L6 donde salen los registros y finaliza el programa.

Los resultados son los siguientes:


Como vemos hay un error en el código que hace a que genere un número más grande de lo esperado, mejoremos el código un poco.

Código Mejorado Código Antiguo
.LC0:
 .string "%d"
 .text
.globl main
 .type main, @function
main:
 pushl %ebp
 movl %esp, %ebp
 andl $-16, %esp
 pushl %esi
 pushl %ebx
 subl $136, %esp
 movl $0, (%esp)
 call time
 movl %eax, (%esp)
 call srand
 movl $0, 124(%esp)
 movl $0, 120(%esp)
 jmp .L2
.L5:
 movl $0, 120(%esp)
 jmp .L3
.L4:
 movl 124(%esp), %ebx
 movl 120(%esp), %esi
 call rand
 movl $954437177, %edx
 imull %edx
 sarl %edx
 movl %ecx, %eax
 sarl $31, %eax
 subl %eax, %edx
 movl %edx, %eax
 sall $3, %eax
 addl %edx, %eax
 movl %ecx, %edx
 subl %eax, %edx
 addl $1, %edx
 movl %ebx, %eax
 sall $2, %eax
 addl %ebx, %eax
 addl %esi, %eax
 movl %edx, 20(%esp,%eax,4)
 addl $1, 120(%esp)
.L3:
 cmpl $5, 120(%esp)
 jle .L4
 addl $1, 124(%esp)
.L2:
 cmpl $5, 124(%esp)
 jle .L5
 movl $0, 124(%esp)
 jmp .L6
.L9:
 movl $0, 120(%esp)
 jmp .L7
.L8:
        movl 124(%esp), %edx
 movl 120(%esp), %ecx
 sall $2, %edx
 addl %edx, %eax
 addl %ecx, %eax
 movl 20(%esp,%eax,4), %edx
 movl $.LC0, %eax
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call printf
 addl $1, 120(%esp)
.L7:
 cmpl $5, 120(%esp)
 jle .L8
 movl $10, (%esp)
 call putchar
 addl $1, 124(%esp)
.L6:
 cmpl $5, 124(%esp)
 jle .L9
 movl $0, %eax
 addl $136, %esp
 popl %ebx
 popl %esi
 movl %ebp, %esp
 popl %ebp
 ret

 .file "matriz.c"
 .section .rodata
.LC0:
 .string "%d"
 .text
.globl main
 .type main, @function
main:
 pushl %ebp
 movl %esp, %ebp
 andl $-16, %esp
 pushl %esi
 pushl %ebx
 subl $136, %esp
 movl $0, (%esp)
 call time
 movl %eax, (%esp)
 call srand
 movl $0, 124(%esp)
 movl $0, 120(%esp)
 movl $0, 124(%esp)
 jmp .L2
.L5:
 movl $0, 120(%esp)
 jmp .L3
.L4:
 movl 124(%esp), %ebx
 movl 120(%esp), %esi
 call rand
 movl %eax, %ecx
 movl $954437177, %edx
 movl %ecx, %eax
 imull %edx
 sarl %edx
 movl %ecx, %eax
 sarl $31, %eax
 subl %eax, %edx
 movl %edx, %eax
 sall $3, %eax
 addl %edx, %eax
 movl %ecx, %edx
 subl %eax, %edx
 addl $1, %edx
 movl %ebx, %eax
 sall $2, %eax
 addl %ebx, %eax
 addl %esi, %eax
 movl %edx, 20(%esp,%eax,4)
 addl $1, 120(%esp)
.L3:
 cmpl $5, 120(%esp)
 jle .L4
 addl $1, 124(%esp)
.L2:
 cmpl $5, 124(%esp)
 jle .L5
 movl $0, 124(%esp)
 jmp .L6
.L9:
 movl $0, 120(%esp)
 jmp .L7
.L8:
 movl 124(%esp), %edx
 movl 120(%esp), %ecx
        movl %edx, %eax
 sall $2, %eax
 addl %edx, %eax
 addl %ecx, %eax
 movl 20(%esp,%eax,4), %edx
 movl $.LC0, %eax
 movl %edx, 4(%esp)
 movl %eax, (%esp)
 call printf
 addl $1, 120(%esp)
.L7:
 cmpl $5, 120(%esp)
 jle .L8
 movl $10, (%esp)
 call putchar
 addl $1, 124(%esp)
.L6:
 cmpl $5, 124(%esp)
 jle .L9
 movl $0, %eax
 addl $136, %esp
 popl %ebx
 popl %esi
 movl %ebp, %esp
 popl %ebp
 ret
 .size main, .-main
 .ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
 .section .note.GNU-stack,"",@progbits

Despues de unas mejoras y quitando un poco de código de debug, el resultado nuevo es el siguiente:


2 comentarios: