1.1 Una ventaja es que el código objeto es abstraído para una maquina virtual. Esta abstracción ayuda a separar operaciones de alto y bajo nivel y realizaciones dependientes de la máquina de igual manera la generación de código y el asignamiento de registros temporales son separados de las RUTINAS SEMANTICAS, las cuales solo trabajan con la abstracción presentada por la representación intermedia. Las dependencias del código objeto son aisladas de las rutinas de generación de código.
1.2 Una ventaja es que la optimización puede ser hecha en el nivel de representación intermedia. Esta organización ayuda a hacer una optimización completamente independiente del código objet, con lo que hace que las trutinas de optimización complejas sean más transportables (Que puedan llevarla de una arquitectura a otra) debido a que las representaciones intermedias son por diseño más abstractas y uniformes, las rutinas de optimización pueden ser más simples.
2. Explique con un ejemplo la optimización de código.
Un ejemplo pequeño de optimización de código es el siguiente caso:
a=1/2; //Código lento no recomendado.
a=0.5; //Código rápido recomendado.
El compilador realiza la división entre 1 y 2 mientras por el contrario el segundo caso es directamente el resultado y no necesita ser procesado.
3. Señale el proceso de compilación de un programa en C#.
Lo primero que le ocurre a un fichero .c de código C es el preprocesado. En este paso se sustituyen todas las macros y se eliminan los comentarios. El resultado, si lo vemos independientemente, es un fichero de código C preprocesado, o .i.
El segundo paso es la compilación propiamente dicha, en el que el código C preprocesado se convierte en código ensamblador, que si lo vemos independientemente es un fichero .s.
El tercer paso es el ensamblado del código ensamblador, lo que lo convierte en código máquina. Un fichero de código máquina también es llamado fichero objeto, y su extensión típica es .o.
Dado que el camino anterior normalmente convierte un fichero en un fichero, se suele hacer en un sólo paso, de código C a fichero objeto.
El último paso es el enlazado de los ficheros objeto en el ejecutable final.
Ejemplo del proceso de compilación
Tomemos el código C más simple posible:
int main(void) /*Ejemplo*/
{
return(0);
}
Al preprocesarlo tendremos:
# 1 "prueba.c"
# 1 "
# 1 "
# 1 "prueba.c"
int main(void)
{
return(0);
}
Vemos que el comentario ha desaparecido. En su lugar aparecen comentarios específicos del preprocesador. Al compilarlo tenemos:
.file "prueba.c"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3)"
.section .note.GNU-stack,"",@progbits
Un precioso código ensamblador que enseguida convertimos en un ilegible código máquina:
ELFØ4( UåäðžÀÀÁèÁà)ÄžÉÃGCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3).symtab.strtab.shstrtab.text.data.bss.comment.note.GNU-stack4#!XX,X95E@Àñÿ
#prueba.cmain
Ese código máquina es el fichero .o que normalmente obtenemos directamente del código C. Finalmente, ese código objeto es enlazado con las librerías necesarias para formar un ejecutable:
ìÀ£žÿÒ¡žÒuëÆŒÉÃöUå¡ÌÀtžÀtäðPTRhhQVhhè³ÿÿÿôUåSQè[ßüÿÿÿÒtè ÿÿÿX[ÉÃUå=Œt+ën_used__libc_start_mainGLIBC_2.0$ii
hÌÿÐÄÉÃUåäðžÀÀÁèÁà)ÄžÉÃUåWVSì
è[Ãþè²þÿÿ ÿÿÿ ÿÿÿ)ÐÁøEðuÄ
[^_]ÃŽ&1ÿÖ¶¿ÿGÆ;}ðrõÄ
[^_]öŒ'UåWVSì
è[Ã ÿÿÿ ÿÿÿ)ÐÁøEðHøÿt41ÿ¶¿ÿGî9}ðuõèDÄ
[^_]ÃUåSR¡Œøÿt»Œ¶¿ÿÐCüëøÿuóX[]ÃUåSPè[ÃþèVþÿÿX[ÉÃÿÿÿÿÿÿÿÿ$
HÀp \
Y
þÿÿo$ÿÿÿoðÿÿoÐÈGCC: (GNU) 4.0.2 (Debian 4.0.2-2)GCC: (GNU) 4.0.2 (Debian 4.0.2-2)GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3)GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3)GCC: (GNU) 4.0.2 (Debian 4.0.2-2)GCC: (GNU) 4.0.3 20051023 (prerelease) (Debian 4.0.2-3)GCC: (GNU) 4.0.2 (Debian 4.0.2-2)°",\
Ô$$̪q!y_IO_stdin_used°Ò../sysdeps/i386/elf/start.S/space/debian/glibc/build-area/glibc-2.3.5/build-tree/glibc-2.3.5/csuGNU AS 2.16.1XÔÔ¬F}xgMint\}nŽO-V|/space/debian/glibc/build-area/glibc-2.3.5/build-tree/i386-libc/csu/crti.S/space/debian/glibc/build-area/glibc-2.3.5/build-tree/glibc-2.3.5/csuGNU AS 2.16.1¬f(/space/debian/glibc/build-area/glibc-2.3.5/build-tree/i386-libc/csu/crtn.S/space/debian/glibc/build-area/glibc-2.3.5/build-tree/glibc-2.3.5/csuGNU AS 2.16.1%
$
>
$
>
4:
;
I?
T/û
../sysdeps/i386/elfstart.S°À01:"VWYX û
init.cš^û
/space/debian/glibc/build-area/glibc-2.3.5/build-tree/i386-libc/csucrti.S3,W\#,:Ô
,Wdd,,W^û
/space/debian/glibc/build-area/glibc-2.3.5/build-tree/i386-libc/csucrtn.Sªq /space/debian/glibc/build-area/glibc-2.3.5/build-tree/glibc-2.3.5/csuinit.cshort intlong long intunsigned charlong long unsigned intshort unsigned int_IO_stdin_usedGNU C 4.0.2 (Debian 4.0.2-2).symtab.strtab.shstrtab.interp.note.ABI-tag.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.text.fini.rodata.eh_frame.ctors.dtors.jcr.dynamic.got.got.plt.data.bss.comment.debug_aranges.debug_pubnames.debug_info.debug_abbrev.debug_line.debug_str#(( 1HH(7
ppP?ÀÀYGÿÿÿo
Tþÿÿo$$ c lD LL
u\\ptt0{°°ä°žžŒ ħÌ̬ÐеºÃ°°
ŒŒÎŒ7×øæp%ö}
v
²0:
'|`!5 Üî(HpÀ$L \
t
°
°žŒÄÌаŒ !Ô
ŒÄ-Ì:ŒIžP
f@
rÀȞ̊`
ŒÐÅŒñÿÖŒñÿéŒñÿúŒñÿ#°*Ž7X
G\
M°
Tc
dŒñÿph#
£ŒñÿªÀñÿ¯ŽŸ°Ë ß call_gmon_start__CTOR_LIST____DTOR_LIST____JCR_LIST__completed.4463p.4462__do_global_dtors_auxframe_dummy__CTOR_END____DTOR_END____FRAME_END____JCR_END____do_global_ctors_aux_DYNAMIC__fini_array_end__fini_array_start__init_array_end_GLOBAL_OFFSET_TABLE___init_array_start_fp_hw__dso_handle__libc_csu_fini_init_start__libc_csu_init__bss_startmain__libc_start_main@@GLIBC_2.0data_start_fini_edata_end_IO_stdin_used__data_start_Jv_RegisterClasses__gmon_start_
4. Generar CI para el código siguiente:
If x>10 and Not(y<0) Then
A+=2
B+=1
End if
for (i=0; i<10; i++){
x += i;
}


