CI-1322 Autómatas y compiladores

Tarea #1

Compilación de un programa

                                                                                                                                                                                  Realizado por :

Roberto Hernández M.   A11727

Jorge Villalta A.   A13959


 

 

 

Contenido

 

Descripción del problema. 2

Comparación y Análisis de las dos versiones de código ensamblador obtenidas. 3

Código Fuente. 7

 

 

 


 

Descripción del problema

      A partir del bloque de código asignado para la tarea ubicado en la dirección http://profesores.ecci.ucr.ac.cr/Luis%20Quesada/CI1322/Tareas/CI1322_Tarea_1.pdf  se obtuvieron 2 programas, uno escrito en Pascal y otro en C++. Se escogió 2 compiladores (Visual C++ 6.0 y Free Pascal) para obtener el lenguaje ensamblador para cada versión del programa.  Se le quitaron las opciones de optimización de código (en los dos casos se le quitaban estas opciones en el menú de opciones del compilador) a cada compilador antes de correrlo y obtener resultados.

      A el código ensamblador obtenido para cada versión del programa se le incluyeron comentarios explicativos que muestran la correspondencia entre el programa fuente y el que produce cada compilador y se señaló claramente el inicio y fin de cada instrucción de lenguaje de alto nivel en lenguaje ensamblador. Finalmente se compararon los resultados obtenidos, y se destacan las diferencias importantes que se encontraron, realizando un análisis sobre los resultados obtenidos.

 



Comparación y Análisis de las dos versiones de código ensamblador obtenidas.

A continuación se hará una breve descripción de las diferencias entre los códigos ensamblador producidos por el compilador de Visual C++ y por el compilador de Free Pascal, así como un análisis de los mismos para determinar si es alguno de los dos más eficiente, y que particularidades tiene cada uno.

Entrando de lleno en materia, se puede observar que el código ensamblador creado en el compilador de C++ comienza declarando las variables utilizadas, mientras que el realizado en el compilador de pascal las define en el segmento de datos ubicado después del código ensamblador.

Antes de iniciar a traducir el lenguaje de alto nivel a ensamblador, los dos compiladores guardan ebp en la pila y mueven el contenido de esp a ebp, pero apartir de aquí se nota otra diferencia, el Free Pascal, llama a un procedimiento llamado FPC_INITIALIZEUNITS mientras que el ensamblador creado por visual C++ realiza todas las operaciones sin hacer ningún llamado a procedimientos.

Es importante recalcar que n en los dos programas fue declarada como constante, pero a la hora de ver el código ensamblador, podemos observar que Visual C++ sí define un n y le asigna el valor de 3000 (definido en el programa fuente) pero más adelante en el código donde hay n lo sustituye por 3000, mientras que el compilador de pascal declara la variable, pero nunca la asigna si no que simplemente sustituye las n’s por 3000.

En este punto se puede observar una gran diferencia en los dos códigos, ya que mientras el código producido por visual C++ logra imprimir un mensaje con 4 líneas de lenguaje ensamblador, el código creado por Free Pascal imprime el mismo mensaje con 37 líneas.

Luego, para representar el for en los dos casos se inicia asignando 1 a la variable numero (que es _numero$ en el ensamblador creado por el compilador de C++ y _NUMERO en el creado por el compilador de pascal.) y en el caso de C++, se hace un salto corto a un una etiqueta $L583 en donde se hace una comparación del  valor de numero con 3000 y si es mayor salta al final de todas las instrucciones del for a la etiqueta $L585 y termina así los ciclos del for. En el caso del compilador de Pascal, se hacen un poco diferentes las cosas ya que después de asignar a numero el valor 1, inicia directamente con las instrucciones dentro del for y se deja al final de estas, la comparación de la variable numero con 3000 para ver si realiza otro ciclo del for o termina el for y continua con la instrucción siguiente.

Una vez dentro del for se pueden ver diferencias todavía más grandes en la forma en que se traducen los códigos en C++ y Pascal a ensamblador, como se verá a continuación:

En las primera línea después del for simplemente se asigna a la variable suma el valor 0 por lo que tanto el compilador de C++ como el de Pascal simplemente asignan ese valor al espacio de memoria asignado a la variable suma.

En la siguiente línea se asigna a la variable temp el valor de la variable numero, que en los dos casos se realiza de la misma forma, en dos instrucciones una que asigna la dirección del valor de numero a un registro y otra que almacena esa dirección de ese registro en el espacio de memoria de la variable temp. La diferencia está en que el código generado por el compilador de C++ utiliza el registro ecx mientras que el creado por el compilador de pascal utiliza el registro di.

En la siguiente línea de código, se inicia el ciclo while. En el caso de C++, se inicia comparando el valor de la variable temp con 0 y si es diferente continúa con la siguiente instrucción dentro del ciclo while, y si no hace un salto hacia el final del ciclo while. Por otro lado, el compilador de pascal nuevamente deja esta comparación para después de todas las instrucciones del while, pero sin embargo hace algo que a mi parecer no es muy eficiente, salta hasta el final de las instrucciones del while para hacer la primera comparación de temp con 0, y luego se devuelve a la primera instrucción del while para continuar con la ejecución de este (en caso de que temp sea diferente de 0, si no termina el while).

En la primera instrucción del while se encuentra una diferencia importante, ya que en el caso de C++ se realiza la operación de asignar a la variable digito el valor de temp modulo 10 en solamente 5 instrucciones de código ensamblador, mientras que el código ensamblador del compilador de pascal realiza la misma instrucción por medio de 8 instrucciones ensamblador dentro de las cuales se incluye una llamada a un procedimiento llamado FPC_BOUNDCHECK que no se especifica de cuantas instrucciones consiste, pero ya se puede notar que el código ensamblador creado por Visual C++ por lo menos para esta instrucción es más eficiente que el creado por Free Pascal.

En la instrucción suma = suma + (digito * digito * digito) se puede observar más claramente que el código ensamblador del compilador de C++ es más eficiente que el de Pascal, ya que esta instrucción consiste simplemente en 6 instrucciones en ensamblador para el código ensamblador de C++, que consisten 3 de ellas en multiplicar el valor de la variable dígito 3 veces, y las otras 3 realizan la suma de este resultado más el valor de la variable suma y almacena el resultado en la variable suma. En cambio en el caso del código generado por Free Pascal, esta misma instrucción en lenguaje de alto nivel se traduce a 17 instrucciones de código ensamblador más 3 posibles llamadas al procedimiento llamado FPC_OVERFLOW (por si las multiplicaciones producen overflow) y una llamada más al procedimiento FPC_BOUNDCHECK. Aquí se observa claramente que debido al menor número de instrucciones en ensamblador, el código emsamblador generado por Visual C++ es más eficiente que el creado por Free Pascal para esta instrucción.

En la instrucción temp = temp / 10 nuevamente vemos que el código ensamblador creado por Visual C++ traduce dicha instrucción a  5 instrucciones en ensamblador, mientras que el código generado por Free Pascal traduce la instrucción a 8 instrucciones en ensamblador y una llamada a un procedimiento llamado FPC_BOUNDCHECK.

En cuanto al IF, el compilador de C++ asigna _suma$ a un registro y lo compara con _numero$ y si no son iguales se salta la escritura del mensaje. Es aquí donde vemos una pequeña diferencia entre los dos compiladores, ya que Free Pascal asigna _SUMA y _NUMERO  a dos registros y compara dichos registros, utilizando una instrucción más para hacer la comparación.

Luego de estas instrucciones el programa termina, en el caso de el código generado por Visual C++ termina el programa sacando los registros guardados en la pila, mientras que el código ensamblador creado por Free Pascal llama al procedimiento FPC_DO_EXIT para terminar el programa y a continuación se ubica el segmento de datos utilizado por el programa, donde se ubica el espacio de memoria asignado para las variables utilizadas en el programa.


Conclusión

En conclusión, se puede observar claramente que el código ensamblador producido por el compilador de C++ es más eficiente que el creado por Free Pascal, ya que como se observó anteriormente algunas instrucciones en código de alto nivel son traducidas en muchas menos instrucciones en código ensamblador por parte del compilador de C++ que  por el compilador de Pascal. Además la manera en que al compilador de Pascal traduce los ciclos while y for es un poco más ineficiente ya que consta de más saltos, que en algunos casos son innecesarios, por lo tanto considero que el compilador de Visual C++ es un poco más eficiente que el de Free Pascal.

 



Código Fuente

 


 

Programa en Pascal

 

PROGRAM Armstrong;

{ RESULTADO

  Determina cuantos números son de Armstrong, desde 1 hasta N.

  - Un número es de Armstrong si la suma de los dígitos que lo

    componen elevados al cubo es igual al número.

  - Por ejemplo 153 es un número de Armstrong porque

           3    3    3

    153 = 1  + 5  + 3  = 1^3 + 5^3 + 3^3  }

CONST

  N = 3000;

VAR

  numero, suma,

  digito, temp : INTEGER;

BEGIN { Armstrong }

  Write('Números encontrados (1 .. ');

  WriteLn(N:1, ') que son de Armstrong:');

  WriteLn;

  FOR numero := 1 TO N DO BEGIN

    suma := 0;

    temp := numero;

    WHILE temp <> 0 DO BEGIN     { suma de dígitos }

      digito := temp MOD 10;     { al cubo         }

      suma   := suma + (digito * digito * digito);

      temp   := temp DIV 10;

    END;

    IF suma = numero THEN BEGIN

      WriteLn(numero,' Suma de sus dígitos al cubo ', suma);

    END;

  END;

END. { Armstrong }

 

 



 

Programa en C++

 

/*programa de prueba para la tarea # 1 de autómatas y compiladores*/

#include <stdio.h>

 

int main(){

 

const int n = 3000;

 

/*Declaro las variables*/

 

int numero, suma, temp, digito;

 

/*imprimo titulo*/

printf("Numeros encontrados ( 1 .. %i ) que son de amstrong\n", n);

/*inicia el programa*/

 

/*inicio del for*/

for(numero = 1; numero <= n; numero++) 

               {

 

               suma = 0;

               temp = numero;

               /*inicio del while*/

               while( temp != 0)

                               {

                               digito = temp % 10;

                               suma   = suma + (digito * digito * digito); 

                               temp   = temp / 10;

                              

                               }

               /*fin del while */

               /*inicio del if*/

               if (suma == numero){

                               printf("%i, suma de sus digitos al cubo, %i\n", numero, suma);

               }

               /*fin del if*/

               }

/*fin del for*/

/*finaliza el programa*/

return 0;

}

 

 



 

Código ensamblador obtenido en Visual C++

 

TITLE     D:\Tarea #1\Amstrong\Amstrong.cpp

               .386P                          

include listing.inc                    

if @Version gt 510                     

.model FLAT                            

else                                    

_TEXT   SEGMENT PARA USE32 PUBLIC 'CODE'

_TEXT   ENDS                           

_DATA  SEGMENT DWORD USE32 PUBLIC 'DATA'

_DATA  ENDS                           

CONST  SEGMENT DWORD USE32 PUBLIC 'CONST'

CONST  ENDS                           

_BSS     SEGMENT DWORD USE32 PUBLIC 'BSS'

_BSS     ENDS                           

$$SYMBOLS       SEGMENT BYTE USE32 'DEBSYM'

$$SYMBOLS       ENDS                   

$$TYPES             SEGMENT BYTE USE32 'DEBTYP'    

$$TYPES             ENDS                           

_TLS      SEGMENT DWORD USE32 PUBLIC 'TLS'

_TLS      ENDS                           

;              COMDAT ??_C@_0DF@JJPP@Numeros?5encontrados?5?$CI?51?5?4?4?5?$CFi?5?$CJ?5@

CONST  SEGMENT DWORD USE32 PUBLIC 'CONST'

CONST  ENDS                           

;              COMDAT ??_C@_0CF@MMOH@?$CFi?0?5suma?5de?5sus?5digitos?5al?5cubo?0@

CONST  SEGMENT DWORD USE32 PUBLIC 'CONST'

CONST  ENDS                           

;              COMDAT _main                   

_TEXT   SEGMENT PARA USE32 PUBLIC 'CODE'

_TEXT   ENDS                           

FLAT      GROUP _DATA, CONST, _BSS       

               ASSUME              CS: FLAT, DS: FLAT, SS: FLAT

endif                                  

PUBLIC _main                          

PUBLIC ??_C@_0DF@JJPP@Numeros?5encontrados?5?$CI?51?5?4?4?5?$CFi?5?$CJ?5@ ; `string'

PUBLIC ??_C@_0CF@MMOH@?$CFi?0?5suma?5de?5sus?5digitos?5al?5cubo?0@ ; `string'

EXTRN  _printf:NEAR                   

EXTRN  __chkesp:NEAR                  

;              COMDAT ??_C@_0DF@JJPP@Numeros?5encontrados?5?$CI?51?5?4?4?5?$CFi?5?$CJ?5@

; File D:\Tarea #1\Amstrong\Amstrong.cpp

CONST  SEGMENT                         

??_C@_0DF@JJPP@Numeros?5encontrados?5?$CI?51?5?4?4?5?$CFi?5?$CJ?5@ DB 'Nu'

               DB          'meros encontrados ( 1 .. %i ) que son de amstrong', 0aH, 00H ; `string'

CONST  ENDS                           

;              COMDAT ??_C@_0CF@MMOH@?$CFi?0?5suma?5de?5sus?5digitos?5al?5cubo?0@

CONST  SEGMENT                        

??_C@_0CF@MMOH@?$CFi?0?5suma?5de?5sus?5digitos?5al?5cubo?0@ DB '%i, suma '

               DB          'de sus digitos al cubo, %i', 0aH, 00H            ; `string'

CONST  ENDS                           

;              COMDAT _main

; Se declaran las variables del programa                   

_TEXT   SEGMENT                        

_n$ = -4                               

_numero$ = -8                          

_suma$ = -12                           

_temp$ = -16                            

_digito$ = -20                         

_main     PROC NEAR                                                                    ; COMDAT

                                       

; l¡nea 4: main() inicio del main en el programa de codigo de m s alto nivel                   

                                       

               push       ebp                    

               mov        ebp, esp               

               sub         esp, 84                                                               ; 00000054H

               push       ebx                    

               push       esi                    

               push       edi                    

               lea          edi, DWORD PTR [ebp-84]

               mov        ecx, 21                                                                ; 00000015H

               mov        eax, -858993460                                               ; ccccccccH

               rep stosd                              

                                                                                                         

; linea 6: const int n = 3000; se asigna 3000 a la variable n                                        

; en caso de el ensamblador la variable n es _n$                                                                 

               mov        DWORD PTR _n$[ebp], 3000                         ; 00000bb8H

                                               

                                

; Se declaran las variables en el lenguaje de alto nivel, en el ensamblador             

; son declaradas en el segmento de datos

; linea 10: int numero, suma, temp, digito;

 

; se imprime mensaje mediante el procedimiento externo _printf                     

; linea 13: printf("Numeros encontrados ( 1 .. %i ) que son de amstrong\n", n);

                                                                  

               push       3000                                                                   ; 00000bb8H

               push       OFFSET FLAT:??_C@_0DF@JJPP@Numeros?5encontrados?5?$CI?51?5?4?4?5?$CFi?5?$CJ?5@ ; `string'

               call          _printf                                           

               add         esp, 8                                            

                                                                  

                                                          

; ******************************inicio del for****************************

                                                                  

; linea 17: for(numero = 1; numero <= n; numero++)                   

                                                                   

               mov        DWORD PTR _numero$[ebp], 1 ;asigna 1 a la variable _numero$                 

               jmp         SHORT $L583                                               

$L584:                                                                     

               mov        eax, DWORD PTR _numero$[ebp]                              

               add         eax, 1                  ;incrementa en 1 la variable _numero$                             

               mov        DWORD PTR _numero$[ebp], eax                      

$L583:                                                             

               cmp        DWORD PTR _numero$[ebp], 3000 ;se compara numero con 3000

               jg            SHORT $L585 ;si es mayor salta a $L585 donde termina el for                                            

                                                                           

                                                                

; linea 20:              suma = 0; se le asigna a _suma$ el valor de 0                                               

                                                                         

               mov        DWORD PTR _suma$[ebp], 0                                

                                                                         

; linea 21:              temp = numero; se le asigna a _temp$ el valor de ecx que                                            

;               es el mismo de _numero$                                                                        

               mov        ecx, DWORD PTR _numero$[ebp]                            

               mov        DWORD PTR _temp$[ebp], ecx                              

$L587:                                                                  

                                                                        

;*********************inicio del while************************************                                     

; linea 23:              while( temp != 0)                                        

                                                                                                   

               cmp        DWORD PTR _temp$[ebp], 0 ; se compara _temp$ con 0 y si es                            

               je            SHORT $L588              ; igual salta a $L588                                       

                                                                  

; linea 25:     digito = temp % 10;                           

                                                                   

               mov        eax, DWORD PTR _temp$[ebp] ; se divide el valor de _temp$                       

               cdq                                                             

               mov        ecx, 10                                                                ; 0000000aH     

               idiv         ecx                                                      

               mov        DWORD PTR _digito$[ebp], edx ; se guarda el residuo en _digito$                     

                                                                              

; linea 26:     suma   = suma + (digito * digito * digito);           

                                                                              

               mov        edx, DWORD PTR _digito$[ebp]                                  

               imul        edx, DWORD PTR _digito$[ebp] ;se multiplica digito 2 veces                                

               imul        edx, DWORD PTR _digito$[ebp] ;por su propio valor                            

               mov        eax, DWORD PTR _suma$[ebp]                        

               add         eax, edx                     ;se suma al resultado el valor de _suma$                      

               mov        DWORD PTR _suma$[ebp], eax   ;se guarda en suma                        

                                                                  

; linea 27:              temp   = temp / 10;                        

                                                                   

               mov        eax, DWORD PTR _temp$[ebp]                        

               cdq                                                       

               mov        ecx, 10                                                              ; 0000000aH

               idiv         ecx                     ;se divide _temp$ entre 10                           

               mov        DWORD PTR _temp$[ebp], eax  ;se guarda el resultado en _temp$                      

                                                                                                                               

                                                                             

               jmp         SHORT $L587   ;salta al inicio del while                                              

$L588:                                                                      

                                                                             

; **************************fin del while***********************************

 

; **************************inicio del if***********************************

 

; linea 32:              if (suma == numero){                                         

                                                                            

               mov        edx, DWORD PTR _suma$[ebp]                                  

               cmp        edx, DWORD PTR _numero$[ebp]  ;se compara _numero$ con _suma                               

               jne          SHORT $L589     ;si no son iguales salta a $L589                                                 

                                                                            

; linea 33:              printf("%i, suma de sus digitos al cubo, %i\n", numero, suma);

                                                                            

               mov        eax, DWORD PTR _suma$[ebp]                                  

               push       eax                                                         

               mov        ecx, DWORD PTR _numero$[ebp]                                

               push       ecx                                               

               push       OFFSET FLAT:??_C@_0CF@MMOH@?$CFi?0?5suma?5de?5sus?5digitos?5al?5cubo?0@ ; `string'

               call          _printf   ;se imprime el mensaje                                            

               add         esp, 12                                                               ; 0000000cH

$L589:                                                            

                                                                  

;****************************fin del if*************************************                                                                                                

                                                                  

               jmp         SHORT $L584   ; salta al inicio del for                                     

$L585:                                                             

                                                                  

;****************************fin del for************************************

                                          

                                           

; linea 39: return 0;                                                

                                                                  

               xor          eax, eax                                          

                                                          

                                              

                                                         

               pop         edi                                      

               pop         esi                                      

               pop         ebx                                       

               add         esp, 84                                                               ; 00000054H

               cmp        ebp, esp

               call          __chkesp

               mov        esp, ebp

               pop         ebp

               ret           0              ; se liberan los registros y retorna 0

_main     ENDP    

_TEXT   ENDS    

END         

;****************************finaliza el programa***************************   

 

 



Código Ensamblador Obtenido en Free Pascal

 

               .386p                     

               LOCALS @@                 

DGROUP               GROUP  _BSS,_DATA        

               ASSUME               CS:_CODE,ES:DGROUP,DS:DGROUP,SS:DGROUP

                                   

               EXTRN   U_SYSWIN32_OUTPUT 

               EXTRN   FPC_WRITELN_END   

               EXTRN   FPC_WRITE_TEXT_SINT

               EXTRN   FPC_WRITE_END

               EXTRN   INIT$$SYSWIN32

               EXTRN   FPC_WRITE_TEXT_SHORTSTR

               EXTRN   FPC_INITIALIZEUNITS

               EXTRN   FPC_IOCHECK

               EXTRN   FPC_OVERFLOW

               EXTRN   FPC_DO_EXIT

               EXTRN   U_SYSWIN32_ISCONSOLE

               EXTRN   FPC_BOUNDCHECK

 

_CODE                  SEGMENT            PARA PUBLIC USE32 'CODE'

               ALIGN 16

; [amstrong.pas]

; [15] BEGIN { Armstrong }

               PUBLIC  _main

_main:

               PUBLIC  PASCALMAIN

PASCALMAIN:

               PUBLIC  program_init

program_init:

                               push        ebp

                               mov         ebp,esp            

                               sub          esp,4             

                               mov         byte ptr [dword ptr U_SYSWIN32_ISCONSOLE],1

                               call          FPC_INITIALIZEUNITS

@@4:

; ************************inicio de escritura de mensaje ******************

; [16] Write('N.meros encontrados (1 .. ');

                               lea           edi,dword ptr [dword ptr U_SYSWIN32_OUTPUT]

                               mov         dword ptr [ebp-4],edi

                               push        offset _$ARMSTRONG$_L7

                               mov         edi,dword ptr [ebp-4]

                               push        edi

                               xor          edi,edi

                               push        edi

                               call          FPC_WRITE_TEXT_SHORTSTR

                               mov         edi,dword ptr [ebp-4]

                               push        edi

                               call          FPC_WRITE_END

                               push        offset @@4

                               call          FPC_IOCHECK

@@8:

; [17] WriteLn(N:1, ') que son de Armstrong:');

                               lea           edi,dword ptr [dword ptr U_SYSWIN32_OUTPUT]

                               mov         dword ptr [ebp-4],edi

                               push        3000

                               mov         edi,dword ptr [ebp-4]

                               push        edi

                               push        1

                               call          FPC_WRITE_TEXT_SINT

                               push        offset _$ARMSTRONG$_L15

                               mov         edi,dword ptr [ebp-4]

                               push        edi

                               xor          edi,edi

                               push        edi

                               call          FPC_WRITE_TEXT_SHORTSTR

                               mov         edi,dword ptr [ebp-4]

                               push        edi   

                               call          FPC_WRITELN_END

                               push        offset @@8

                               call          FPC_IOCHECK

@@16:                         

; [18] WriteLn;               

                               lea           edi,dword ptr [dword ptr U_SYSWIN32_OUTPUT]

                               mov         dword ptr [ebp-4],edi

                               push        edi   

                               call          FPC_WRITELN_END

                               push        offset @@16

                               call          FPC_IOCHECK

 

;************************inicio de escritura de mensaje *******************

 

; [19] FOR numero := 1 TO N DO BEGIN

 

;*************************inicio del for***********************************

 

                               mov         word ptr [dword ptr _NUMERO],1 ; asigna 1 a _NUMERO

               ALIGN 4                                                           

@@19:                                                                      

; [20] suma := 0;             

                               mov         word ptr [dword ptr _SUMA],0 ; asigna 0 a _SUMA

; [21] temp := numero;                                            

                               mov         di,word ptr [dword ptr _NUMERO]     

                               mov         word ptr [dword ptr _TEMP],di   ;asigna _NUMERO a _TEMP 

                             

;************************ inicio del while*********************************

                             

; [22] WHILE temp <> 0 DO BEGIN     { suma de d.gitos }                       

                               jmp          @@27 ;salta a @@27 para hacer la comparaci¢n    

@@26:                                                              

; [23] digito := temp MOD 10;     { al cubo         }              

                               movsx      eax,word ptr [dword ptr _TEMP]

                               mov         edi,10          

                               cdq                     

                               idiv          edi             

                               mov         ecx,edx         

                               mov         edi,offset R_31 

                               call          FPC_BOUNDCHECK                 

                               mov         word ptr [dword ptr _DIGITO],dx; se guarda en _DIGITO

                                                                      ;el valor del residuo

; [24] suma   := suma + (digito * digito * digito);                         

                               movsx      eax,word ptr [dword ptr _DIGITO]                    

                               movsx      edx,word ptr [dword ptr _DIGITO];se multiplica DIGITO por                      

                               imul         edx,eax                         ;su propio valor                         

                               jno           @@34                                               

                               call          FPC_OVERFLOW                                       

@@34:                                                                       

                               movsx      eax,word ptr [dword ptr _DIGITO];se vuelve a multiplicar                   

                               imul         eax,edx                         ;digito por el mismo                      

                               jno           @@35                                                

                               call          FPC_OVERFLOW                                       

@@35:                                                                      

                               movsx      edx,word ptr [dword ptr _SUMA]                     

                               add          edx,eax                                             

                               jno           @@36                            

                               call          FPC_OVERFLOW                    

@@36:                                                   

                               mov         ecx,edx                         

                               mov         edi,offset R_31                 

                               call          FPC_BOUNDCHECK                   

                               mov         word ptr [dword ptr _SUMA],dx  ; se suma _SUMA a el resultado

                                                                      ; anterior y se guarda en _SUMA  

; [25] temp   := temp DIV 10;                                                        

                               movsx      eax,word ptr [dword ptr _TEMP]                               

                               mov         edi,10                                                       

                               cdq                                                                  

                               idiv          edi                                                           

                               mov         ecx,eax                                                      

                               mov         edi,offset R_31                                              

                               call          FPC_BOUNDCHECK                                               

                               mov         word ptr [dword ptr _TEMP],ax ;se guarda en _TEMP el

                                                                     ;valor de temp / 10

@@27:                                                                                

                               movsx      eax,word ptr [dword ptr _TEMP]                               

                               test          eax,eax                      ;comparacion del while                            

                               jne           @@26               ;si no es igual repite el while

                              

;***************************fin del while*************************************

                              

                              

@@28:

;***************************inicio del if*************************************                                                                                

 

; [27] IF suma = numero THEN BEGIN                                           

                               movsx      eax,word ptr [dword ptr _SUMA]                  

                               movsx      edx,word ptr [dword ptr _NUMERO]                

                               cmp         edx,eax   ;se compara _SUMA con _NUMERO                                        

                               jne           @@40     ;si no es igual salta a @@40                                        

@@41:                                                                   

; [28] WriteLn(numero,' Suma de sus d.gitos al cubo ', suma);

 

;***************************inicio de escritura de mensaje********************           

 

                               lea           edi,dword ptr [dword ptr U_SYSWIN32_OUTPUT]     

                               mov         dword ptr [ebp-4],edi                           

                               movsx      eax,word ptr [dword ptr _NUMERO]                

                               push        eax                                             

                               mov         edi,dword ptr [ebp-4]               

                               push        edi                                 

                               xor          edi,edi                             

                               push        edi                                 

                               call          FPC_WRITE_TEXT_SINT                 

                               push        offset _$ARMSTRONG$_L46             

                               mov         edi,dword ptr [ebp-4]                

                               push        edi                                 

                               xor          edi,edi                             

                               push        edi                                 

                               call          FPC_WRITE_TEXT_SHORTSTR             

                               movsx      eax,word ptr [dword ptr _SUMA]      

                               push        eax                                  

                               mov         edi,dword ptr [ebp-4]               

                               push        edi                                 

                               xor          edi,edi                             

                               push        edi                                 

                               call          FPC_WRITE_TEXT_SINT                 

                               mov         edi,dword ptr [ebp-4]

                               push        edi  

                               call          FPC_WRITELN_END

                               push        offset @@41

                               call          FPC_IOCHECK

 

;**************************fin de escritura de mensaje************************

 

@@40:    ;comparaci¢n del for                                                                     

                               cmp         word ptr [dword ptr _NUMERO],3000 ;se compara _NUMERO

                               jge           @@18                              ;con 3000, si es mayor                   

                               inc           word ptr [dword ptr _NUMERO]      ;salta a @@18 y termina                    

                               jmp          @@19                              ;si no salta a @@19 y                       

@@18:                                                     ;repite el for     

              

;*************************termina el for**************************************

; [31] END. { Armstrong }                                                    

                               call          FPC_DO_EXIT

@@49:                        

                               leave        

                               ret          

               ALIGN 16             

_CODE                  ENDS         

                             

_DATA                  SEGMENT            PARA PUBLIC USE32 'DATA'

                               DB          "FPC 1.0.10 [2003/06/27] for i386 - WIN32"

               ALIGN 4

R_31       DD          -32768,32767

               PUBLIC  FPC_RESOURCESTRINGTABLES

FPC_RESOURCESTRINGTABLES   DD          0                                        

               PUBLIC  INITFINAL                                                         

INITFINAL           DD          1,0                                                      

                               DD          offset INIT$$SYSWIN32                                    

                                                                                 

               DD          0                                                                 

               PUBLIC  HEAPSIZE                                                         

HEAPSIZE             DD          2097152                                                  

               PUBLIC  __stklen                                                          

__stklen   DD          131072                                                   

_DATA                  ENDS                                                             

                                                                                 

_DATA                  SEGMENT            PARA PUBLIC USE32 'DATA'                                 

_$ARMSTRONG$_L7                        DB          26,"N",250,"meros encontrados (1 .. ",0          

_$ARMSTRONG$_L15                      DB          23,") que son de Armstrong:",0           

_$ARMSTRONG$_L46                      DB          29," Suma de sus d",237,"gitos al cubo ",0

_DATA                  ENDS               

                                   

_DATA                  SEGMENT            PARA PUBLIC USE32 'DATA'

_DATA                  ENDS               

;declaracion de las variables usadas

_BSS                      SEGMENT            PARA PUBLIC USE32 'BSS'

_NUMERO                           DB          2 DUP(?)

_SUMA                 DB          2 DUP(?)

_DIGITO                               DB          2 DUP(?)

_TEMP                  DB          2 DUP(?)

               PUBLIC  HEAP

HEAP                     DB          2097152 DUP(?)

_BSS                      ENDS

               END