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: