Sistemas Embebidos: Teoría, Implementación y Metodologías de Diseño

UNIVERSIDAD NACIONAL DE COLOMBIA

Carlos Iván Camargo Bareño

18 de junio de 2010

Informe Final Sistemas Embebidos: Teoría, Implementación y Metodologías de Diseño Author: C. Camargo e-mail: cicamargoba@unal.edu.co

Copyright \begin{matrix}c \\ ◯ \end{matrix}2004, 2005 Universidad Nacional de Colombia

http://www.unal.edu.co

Permission is granted to copy, distribute and/or modify this document under the terms of the gnu Free Documentation License, version 1.2, with no invariant sections, no front-cover texts, and no back-cover texts. A copy of the license is included in the end.

This document is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.

Published by the Universidad Nacional de Colombia

Índice general

1. Introducción 3

2. Conceptos Básicos de los Sistemas Embebidos 7 2.1. Definición . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2. Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.3. Arquitectura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.4. Metodología de Diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.4.1. Herramientas Software de libre distribución GNU toolchain . . . . . . . . . . . . 10 2.4.2. Componentes del GNU toolchain . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4.3. GNU binutils[1] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4.4. GNU Compiler Collection[2] . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.4.5. GNU Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.4.6. C Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.5. Obtención y utilización del GNU toolchain . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.5.1. Conceptos Previos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.5.2. Flujo de diseño software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.5.3. El formato ELF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.5.4. Herramienta de compilación make . . . . . . . . . . . . . . . . . . . . . . . . . . 17

Capítulo 1

Introducción

La industria de los semiconductores ha crecido velozmente durante los últimos años, su campo de acción se ha extendido a casi todas las actividades del ser humano (Entretenimiento, salud, seguridad, transporte, educación, etc); los tiempos de los procesos de diseño son cada vez mas cortos, lo cual require herramientas Hardware, Software y metodologías de diseño que ayuden a cumplir con las exigencias impuestas al sistema.

Esta invasión digital ha sido posible gracias a la industria de los semiconductores y a las empresas desarrolladoras de software, las primeras haciendo uso de un altísimo grado de integración ponen a disposición de los diseñadores Systems On Chip (SoC) en los cuales se integran procesadores de 32 bits con una gran variedad de periféricos tales como: Controladores de dispositivos de red (cableada e inalámbricos), controladores de video, procesadores aritméticos, controladores de memorias (Flash, SDRAM, DDR, USB, SD), codecs de audio, controladores de touch screen, etc; lo cual permite la implementación de aplicaciones completas dentro de uno de estos SoCs.

Por otro lado, las empresas desarrolladoras de SW crean herramientas de programación que permiten manejar toda la capacidad de estos SoCs. colocando a disposición de los diseñadores: compiladores, simuladores, emuladores, librerías, Sistemas Operativos y drivers. Lo cual permite realizar desarrollos complejos en tiempos cortos.

En la actualidad existe un gran número de sistemas operativos (OS) disponibles tanto comerciales como open source. La figura 1.1 muestra la utilización actual de OS comerciales en aplicaciones embebidas; si sumamos los sistemas operativos basados en linux se obtiene un valor del 19.3 % lo cual hace ganador al sistema operativo de libre distribución [3]. La figura 1.2 muestra un cuadro comparativo de la utilización de herramientas comerciales y linux; de nuevo se observa que linux es el preferido por los diseñadores. Este resultado es interesante ya que uno de los supuestos puntos débiles del software de libre distribución es el soporte, lo cual no lo hace tan agradable a la hora de realizar aplicaciones comerciales, sin embargo, esto es solo un mito, ya que gracias a que el código fuente está disponible, es posible comprender perfectamente su funcionamiento, lo cual no sucede con el software comercial; además, existen muchos foros de diseñadores y desarrolladores que se encargan de responder las inquietudes, estos foros almacenan todos los mensajes recibidos e incluyen herramientas de búsqueda para poder consultarlos, por regla general de estos foros, se debe buscar primero en estos archivos históricos, muy seguramente alguien más preguntó lo mismo antes que nosotros.

El caracter gratutito de las herramientas de libre distribución no significa, ni mucho menos, mala calidad, todo lo contrario, existen muchas personas que escudriñan su código fuente en búsqueda de posibles errores, y realizan cambios con el fín de eliminarlo; por lo tanto, se cuenta con miles de personas que están constantemente depurando y perfeccionando una determinada aplicación; esto no ocurre con el software comercial, normalmente el soporte hay que pagarlo y las perosnas involucradas en el desarrollo no son tantas como las que tienen acceso al código fuente del software libre. Por esta razón empresas como PALM, han dejado de lado productos propietarios como el PALM OS para utilizar linux, SUN Microsystems, liberó el código fuente de su sistema operativo Solaris, ya que no era comparable con linux y está en el proceso de liberar uno de sus procesadores.

Figura 1.1: Utilización actual de OS para aplicaciones embebidas: Fuente [4].

De lo anterior se deduce que el mundo de los sistemas digitales ha cambiado en forma considerable, y que en la actualidad existen grandes facilidades para el desarrollo de productos de forma rápida y económica 1. Desafortunadamente estas tendencias no se han aplicado aún en Colombia; existen varias razones para esto:

1. Desactualización de los programas acedémicos: En muchas de las Universidades de Colombia se utilizan tecnologías obsoletas que impiden la aplicación de metodologías de diseño modernas además de impedir el desarrollo de aplicaciones comerciales, un ejemplo de este tipo de tecnologías es la lógica TTL (74XX) y sus equivalentes en CMOS. Aunque vale la pena aclarar que este tipo de tecnología es útil a la hora de enseñar conceptos básicos, no puede ser utilizada como única herramienta de implementación. Un ejemplo de desactualización de metodologías de diseño lo encontramos en las herramientas de programación para microcontroladores, una gran cantidad de Universidades utilizan lenguaje ensamblador, lo cual impide la re-utilización de código y crea dependencias con el HW utilizado.

2. Falta de interés de la Industria: Un gran porcentaje de la industria Colombiana es consumidora de tecnología, es decir, no generan sus propias soluciones, no cuentan con departamentos de Investigación y Desarrollo; esto se debe a la falta de confianza en los productos nacionales y en algunos casos a la inexistencia de producción nacional. Por otro lado, la cooperación entre la Universidad y la industria es muy reducida, debido a falta de políticas en las Universidades que regulen esta actividad y a la poca inversión por parte de las empresas.

3. Políticas del Estado: Casi la totalidad de estos nuevos dispositivos semiconductores deben ser importados, ya que en Colombia no existen distribuidores, por lo tanto, es necesario pagar una serie de impuestos que no desalientan su utilización, estos impuestos están por el orden del 26 % del valor del producto. Por otro lado la apertura económica permite que ingresen productos a bajo precio, con los que no pueden competir los pocos productos desarrollados en el pais, eso sumado a la falta de protección por parte de las políticas estatales condena a los desarrolladores de estos sistemas a la quiebra económica.

Este proyecto resume el trabajo realizado durante los últimos cuatro años en el área de la electrónica digital y más exactamente en el estudio de las metodologías de diseño modernas con aplicaciones comer-

1En la actualidad cerca del 60 % de los ingenieros trabajan en compañías con menos de 10 desarrolladores de SW [5]

Figura 1.2: Utilización actual de OS para aplicaciones embebidas: Fuente http://www.linuxdevices.com/articles/AT7070519787.html. ciales y es presentado para cumplir parcialmente los requisitos de cambio de categoría de profesor asistente a asociado. El presente informe está dividido de la siguiente forma:

En el capítulo 1 se realiza una breve descripción de los sistemas embebidos, se enumeran sus características, aplicaciones y se hace una descripción de las herramientas HW y SW necesarias para el diseño de los mismos. En los capítulos siguientes se desarrollan casos de estudio encaminados a la comprensión de estos sistemas:

En el capítulo dos se trabaja con una plataforma comercial de bajo costo: El GameBoy de Nintendo, (gracias a los elevados volúmenes de producción el costo de este dispositivo es bajo alrededor de 40 USD) esta plataforma nos permite desarrollar conceptos básicos como la compilación cruzada, la interfaz HW-SW y los sistemas operativos.

En el capítulo tres se muestra la implementación de la primera plataforma de desarrollo para sistemas embebidos diseñada en la Universidad Nacional, a pesar de ser muy sencilla permite dar un gran paso en el proceso de fabricación de este tipo de dispositivos.

En el capítulo cuatro se realiza la implementción de una plataforma de desarrollo que utiliza el sistema operativo linux sobre un arreglo de compuertas programable en campo (FPGA) y se muestran los resultados de una aplicación en el área del Hardware Reconfigurable.

El capítulo cinco es una guía de adaptación del sistema operativo linux para una arquitectura ARM.

Por último se muestra como algunos de los resultados de este estudio han sido introducidos a los cursos del área de los sistemas digitales en la Universidad Nacional de Colombia y como se ha realizado su difusión en otras Universidades de Colombia.

Capítulo 2

Conceptos Básicos de los Sistemas Embebidos

2.1. Definición

Un Sistema Embebidos es un sistema de propósito específico en el cual, el computador es encapsulado completamente por el dispositivo que el controla. A diferencia de los computadores de propósito general, un Sistema Embebido realiza tareas pre-definidas, lo cual permite su optimización, reduciendo el tamaño y costo del producto [2]

2.2. Características

Los sistemas embebidos son diseñados para una aplicación específica, es decir, estos sistemas realizan un grupo de funciones previamente definidasm y una vez el sistema es diseñado, no se puede cambiar su funcionalidad. Por ejemplo, el control de un asensor siempre realizará las mismas acciones durante su vida útil.

Debido a su interacción con el entorno los ES deben cumplir esctríctamente restricciones temporales. El término Sistemas de Tiempo Real es utilizado para enfatizar este aspecto.

Los Sistemas Embebidos son heterogéneos, es decir, están compuestos por componentes Hardware y Software. Los componentes Hardware, como ASICs y Dispositivos Lógicos Programables (PLD) proporcionan la velocidad de ejecución y el cosumo de potencia necesarios en algunas aplicaciones.

Los Sitemas Embebidos tienen grandes requerimientos en términos de confiabilidad. Errores en aplicaciones como la aviación y el automovilismo, pueden tener consecuencias desastrosas.

2.3. Arquitectura

Una arquitectura típica para un Sistema Embebido se muestra en la Figura 2.1; La cual integra un componente hardware, implementado ya sea en un PLD (CPLD, FPGA) o en un ASIC, conocido con el nombre de periféricos y un componente software (procesador o DSP) capáz de ejecutar software, la parte del procesador está dividida en la CPU (En algunos casos posee una caché) y las unidades de Memoria.

Figura 2.1: Arquitectura de un Sistema Embebido

Al momento de diseñar un Sistema Embebido encontramos las siguientes opciones:

Componente HW y SW Integrado en un dispositivo semiconductor (SoC): En la actualidad existen muchas compañías que fabrican procesadores de 32 bits integrados a una gran variedad de periféricos, lo cual simplifica el diseño y reduce costos (menos componentes y menos área de circuito impreso) 1.

Componente SW en un SoC y componente HW en una FPGA: Cuando no existen en el mercado SoC con la cantidad de periféricos requerida para una determinada aplicación, es necesario recurrir a la utilización de dispositivos comerciales que implementen dicha operación, en algunas ocaciones el periférico puede relizar funciones muy específicas de modo que no existe en el mercado, la solución es entonces implementar estos dispositivos en una FPGA, también se recomienda la utilización de FPGAs en sistemas que requieren una gran cantidad y variedad de periféricos ya que reduce la complejidad y costo del sistema.

Componente SW y HW en una FPGA: Esta es tal vez la opción más económica y flexible, pero la de menor desempeño, ya que al utilizar los recursos lógicos de la FPGA para la implementación del procesador (softcore) la lngitud de los caminos de interconexión entre los bloques lógicos aumentan el retardo de las señales . Los procesadores softcore más populares en la actualidad son:

• Microblaze de Xilinx^{2}

• Leon de Gaisler Research^{3}

• LatticeMico32 de Lattice Semiconductors^{4}

• OpenRisc^{5}

2.4. Metodología de Diseño

La Figura 2.2, muestra un diagrama de flujo genérico para diseño para sistemas embebidos [?]

Figura 2.2: Flujo de Diseño de un Sistema Embebido

El proceso comienza con la especificación del sistema, en este punto se describe la funcionalidad y se definen las restricciones físicas, eléctricas y económicas. Esta especificación debe ser muy general y no deben existir dependencias (tecnológicas, metodológicas) de ningún tipo, se suele utilizar lenguajes de alto nivel, como UML, C++. La especificación puede ser verificada a través de una serie de pasos de análisis cuyo objetivo es determinar la validez de los algorítmos seleccionados, por ejemplo, determinar si el algoritmo siempre termina, los resultados satisfacen las especificaciones. Desde el punto de vista de la re-utilización, algunas partes del funcionamiento global deben tomarse de una librería de algorítmos existentes.

1http://www.sharpsma.com, http://www.atmel.com, http://www.cirrus.com, http://www.samsung.com, http://www.freescale.com, etc

2http://www.xilinx.com 3http://www.gaisler.com/ 4http://www.latticesemi.com 5http://www.opencores.com

Una vez definidas las especificaciones del sistema se debe realizar un modelamiento que permita extraer de estas la funcionalidad. El modelamiento es crucial en el diseño ya que de él depende el paso existoso de la especificación a la implementación. Es importante definir que modelo matemático debe soportar el entorno de diseño. Los modelos más utilizados son: Máquinas de estados finitos, diagramas de flujos de datos, Sistemad de Eventos Discretos y Redes de Petri. Cada modelo posee propiedades matemáticas que pueden explotarse de forma eficiente para responder preguntas sobre la funcionalidad del sistema sin llevar a cabo dispendiosas tareas de verificación. Todo modelo obtenido debe ser verificado para comprobar que cumple con las restricciones del sistema.

Una vez se ha obtenido el modelo del sistema se procede a determinar su arquitectura, esto es, el número y tipo de componentes y su inter-conexión. Este paso no es más que una exploración del espacio de diseño en búsqueda de soluciones que permitan la implementación de una funcionalidad dada, y puede realizarse con varios criterios en mente: Costos, confiabilidad, viabilidad comercial.

Utilizando como base la arquitectura obtenida en el paso anterior las tareas del modelo del sistemas son mapeadas dentro de los componentes. Esto es, asignación de funciones a los componentes de la arquitectura. Existen dos opciones a la hora de implementar las tareas o procesos:

1. Implementación Software: La tarea se va a ejecutar en un procesador.

2. Implementación Hardware: La tarea se va a ejecutar en un sistema digital dedicado.

Para cumplir las especificaciones del sistema algunas tareas deben ser implementadas en Hardware, esto con el fín de no ocupar al procesador en tareas cíclicas, un ejemplo típico de estas tareas es la generación de bases de tiempos. La decisión de que tareas se implementan en SW y que tareas se implementan en HW recibe el nombre de particionamiento, esta selección es fuertemente dependiente de restricciones económicas y temporales.

Las tareas Software deben compartir los recursos que existan en el sistema (procesador y memoria), por lo tanto se deben hacer decisiones sobre el orden de ejecución y la prioridad de estas. Este proceso recibe el nombre de planificación. En este punto del diseño el modelo debe incluir información sobre el mapeo, el particionamiento y la planificación del sistema.

Las siguientes fases corresponden a la implementación del modelo, para esto las tareas hardware deben ser llevadas al dispositivo elegido (ASIC o FPGA) y se debe obtener el ′′ejecutable′′ de las tareas software, este proceso recibe el nombre de síntesis HW y SW respectivamente, así mismo se deben sintetizar los mecanismos de comunicación.

El proceso de prototipado consiste en la realización física del sistema, finalmente el sistema físico debe someterse a pruebas para verificar que se cumplen con las especificaciones iniciales.

Como puede verse en el flujo de diseño existen realimentaciones, estas realimentaciones permiten depurar el resultado de pasos anteriores en el caso de no cumplirse las especificaciones iniciales

2.4.1. Herramientas Software de libre distribución GNU toolchain

En el mercado existe una gran variedad de herramientas de desarrollo para Sistemas Embebidos, sin embargo, en este estudio nos centraremos en el uso de las herramientas de libre distribución; esta elección se debe a que la mayoría de los productos comerciales utilizan el toolchain de GNU^{6} internamente y proporcionan un entorno gráfico para su fácil manejo. Otro factor considerado a la hora de realizar nuestra elección es el económico, ya que la mayoría de los productos comerciales son costosos y poseen soporte limitado. Por otro lado, el toolchain de GNU es utilizado ampliamente en el medio de los diseñadores de sistemas embebidos y se encuentra un gran soporte en múltiples foros de discusión (ver Figura 2.3).

Figura 2.3: Tendencia de utilización de herramientas de desarrollo

2.4.2. Componentes del GNU toolchain

2.4.3. GNU binutils[1]

Son una colección de utilidades para archivos binarios y estan compuestas por:

addr2line Convierte direcciones de un programa en nombres de archivos y números de línea. Dada una dirección y un ejecutable, usa la información de depuración en el ejecutabe para determinar que nombre de atchivo y número de lpinea está asociado con la dirección dada.

ar Esta utilidad crea, modifica y extrae desde ficheros. Un fichero es una colección de otros archivos en una estructura que hace posible obtener los archivos individuales miembros del archivo.

as Utilidad que compila la salida del compilador de C (GCC).

c++filt Este program realiza un mapeo inverso: Decodifica nombres de bajo-nivel en nombres a nivel de usuario, de tal forma que el linker pueda mantener estas funciones sobrecargadas (overloaded) “from clashing”.

gasp GNU Assembler Macro Preprocessor

ld El linker GNU combina un número de objetos y ficheros, re-localiza sus datos y los relaciona con referencias. Normalmente el último paso en la construcción de un nuevo programa compilado es el llamado a ld.

nm Realiza un listado de símbolos de archivos tipo objeto.

objcopy Copia los contenidos de un archivo tipo objeto a otro. objcopy utiliza la librería GNU BFD para leer y escribir el archivo tipo objeto. Permite esccribibr el archivo destino en un formato diferente al del archivo fuente.

objdump Despliega información sobre archivos tipo objeto.

ranlib Genera un índice de contenidos de un fichero, y lo almacena en él.

readelf Interpreta encabezados de un archivo ELF. size Lista el tamaño de las secciones y el tamaño total de un archivo tipo objeto. strings Imprime las secuencias de caracteres imprimibles de almenos 4 caracteres de longitud. strip Elimina todos los símbolos de un archivo tipo objeto.

6http://www.gnu.org

2.4.4. GNU Compiler Collection[2]

El GNU Compiler Collection normalmente llamado GCC, es un grupo de compiladores de lenguajes de programación producido por el proyecto GNU. Es el compilador standard para el software libre de los sistemas operativos basados en Unix y algunos propietarios como Mac OS de Apple.

Lenguajes GCC soporta los siguientes lenguajes: ADA C C++ Fortran Java Objective-C Objective-C++

Arquitecturas Alpha ARM Atmel AVR Blackfin H8/300 System/370, System/390 IA-32 (x86) and x86-64 IA-64 i.e. the Ïtanium” Motorola 68000 Motorola 88000 MIPS PA-RISC

PDP-11

PowerPC

SuperH

SPARC

VAX

Renesas R8C/M16C/M32C

MorphoSys

Como puede verse GCC soporta una gran cantidad de lenguajes de programación, sin embargo, en el presente estudio solo lo utilizaremos como herramienta de compilación para C y C++. Una característica de resaltar de GCC es la gran cantidad de plataformas que soporta, esto lo hace una herramienta Universal para el desarrollo de sistemas embebidos, el código escrito en una plataforma (en un lenguaje de alto nivel) puede ser implementado en otra sin mayores cambios, esto elimina la dependencia entre el código fuente y el HW^{7}, lo cual no ocurre al utilizar lenguaje ensamblador.

Por otro lado, el tiempo requerido para realizar aplicaciones utilizando C o C++ disminuye, ya que no es necesario aprender las instrucciones en assembler de una plataforma determinada; además, la disponibilidad de librerías de múltiples propósitos reduce aún más los tiempos de desarrollo, permitiendo de esta forma tener bajos tiempos time to market y reducir de forma considerable el costo del desarrollo. Una consecuencia de esto se refleja en el número de desarrolladores en un grupo de trabajo, en la actualidad casi el 60 % de las empresas desarrolladoras de dispositivos embebidos tiene grupos con menos de 10 desarrolladores 2.4.

Figura 2.4: Número promedio de desarrolladores por compañía. Fuente Venture Development Corp

2.4.5. GNU Debugger

El depurador oficial de GNU (GDB), es un depurador que al igual que GCC tiene soporte para múltiples lenguajes y plataformas. GDB permite al usuario monitorear y modificar las variables internas del programa y hacer llamado a funciones de forma independiente a la ejecución normal del mismo. Además, permite establecer sesiones remotas utilizando el puerto serie o TCP/IP. Aunque GDB no posee una interfaz gráfica, se han desarrollado varios front-ends como DDD o GDB/Insight. A continuación se muestra un ejemplo de una sesión con gdb.

GNU gdb Red Hat Linux ( 6 . 3 . 0 . 0 − 1 . 2 1rh )
C o p y r i g h t 2004 Free S o f t w a r e Foundation , I n c .
GDB i s f r e e s o f t w a r e , covered by t h e GNU General P u b l i c License , and you a r e
welcome t o change i t and /or d i s t r i b u t e c o p i e s of i t under c e r t a i n c o n d i t i o n s .
Type ”show copying ” t o s e e t h e c o n d i t i o n s .
There i s a b s o l u t e l y no w a r r a n t y f o r GDB. Type ”show w a r r a n t y ” f o r d e t a i l s .
This GDB was c o n f i g u r e d as ”i386−r e d h a t−l i n u x−gnu” … Using h o s t l i b t h r e a d d b
l i b r a r y ”/l i b /l i b t h r e a d d b . so . 1 ”.

7Esto recibe el nombre de re-utilización de código

Universidad Nacional de Colombia 12

( gdb ) run
S t a r t i n g program : /home/sam /programming /c r a s h
Reading symbols from s h a r e d o b j e c t r e a d from t a r g e t memory … done .
Loaded system s u p p l i e d DSO a t 0xc11000
This program w i l l d e m o n s t r a t e gdb
Program r e c e i v e d s i g n a l SIGSEGV, S e g m e n t a t i o n f a u l t .
0x08048428 i n f u n c t i o n 2 (x=24) a t c r a s h . c : 2 2
22  return ∗y ;
( gdb ) e d i t
( gdb ) s h e l l gcc c r a s h . c −o c r a s h −g s t a b s+
( gdb ) run
The program being debugged has been s t a r t e d a l r e a d y .
S t a r t i t from t h e b e g i n n i n g ? (y or n) y
warning : c a n n o t c l o s e ”s h a r e d o b j e c t r e a d from t a r g e t memory”: F i l e i n wrong f o r m a t
‘ /home/sam /programming /c r a s h ’ has changed ; re−r e a d i n g symbols .
S t a r t i n g program : /home/sam /programming /c r a s h
Reading symbols from s h a r e d o b j e c t r e a d from t a r g e t memory … done .
Loaded system s u p p l i e d DSO a t 0xa3e000
This program w i l l d e m o n s t r a t e gdb

24

Program e x i t e d n o r m a l l y .
( gdb ) q u i t

2.4.6. C Libraries

Adicionalmente es necesario contar con una librería que proporcione las librerías standard de C: stdio, stdlib, math; las más utilizadas en sistemas embebidos son:

glibc^{8} Es la librería C oficial del proyecto GNU. Uno de los inconvenientes al trabajar con esta librería en sistemas embebidos es que genera ejecutables de mayor tamaño que los generados a partir de otras librerías, lo cual no la hace muy atractiva para este tipo de aplicaciones.

uClibc^{9} Es una librería diseñada especialmente para sistemas embebidos, es mucho más pequeña que glibc.

newlib^{10} Al igual que uClibc, está diseñada para sistemas embebidos. El típico “Hello, world!” ocupa menos de 30k en un entorno basado en newlib, mientras que en uno basado en glibc, puede ocupar 380k [6].

diet libc^{11} Es una versión de libc optimizada en tamaño, puede ser utilizada para crear ejecutables estáticamente enlazados para linux en plataformas alpha, arm, hppa, ia64, i386, mips, s390, sparc, sparc64, ppc y x86 64.

2.5. Obtención y utilización del GNU toolchain

El primer paso en nuestro estudio consiste en tener una cadena de herramientas funcional que soporte la familia de procesadores a utilizar. La arquitectura sobre la cual realizaremos nuestra investigación es la ARM (Advanced Risc Machines), ya que un la más utilizada en la actualidad por los diseñadores de sistemas embebidos (ver figura 2.5) y se encuentran disponibles una gran variedad de herramientas para esta arquitectura. Existen dos formas de obtener la cadena de herramientas GNU:

Figura 2.5: Tendencia del mercado de procesadores para sistemas embebidos. Fuente:[7]

8http://www.gnu.org/software/libc/ 9http://uclibc.org/ 10http://sources.redhat.com/newlib/ 11http://www.fefe.de/dietlibc/ 1. Utilizar una distribución precompilada: Esta es la via más rápida, sin embargo, hay que tener cuidado al momento de instalarlas,

ya que debe hacerse en un directorio con el mismo path con el que fueron creadas. por ejemplo /usr/local/gnutools; si esto no se cumple, las herramientas no funcionarán de forma adecuada.

2. Utilizar un script de compilación: Existen disponibles en la red una serie de scripts que permiten descargar, configurar, compilar e instalar la cadena de herramientas, la ventaja de utilizar este método es que es posible elegir las versiones de las herramientas instaladas, al igual que el directorio de instalación. En este estudio utilizaremos los scripts creados por Dan Kegel [8].

2.5.1. Conceptos Previos

Antes de abordar el uso de las herramientas GNU hablaremos sobre varios conceptos que deben quedar claros para un mejor entendimiento de la función de estas herramientas; el flujo de diseño software, es decir, los pasos que deben seguirse para la implementación de una tarea software desde sus concepción hasta su implementación en un Procesador, microcontrolador o DSP.

2.5.2. Flujo de diseño software

En la figura 2.6 se ilustra la secuencia de pasos que se realizan desde la creación de un archivo de texto que posee el código fuente que implementa la funcionalidad de una tarea software utilizando un lenguaje de alto nivel como C o C++, hasta su programación en una memoria permanente en la plataforma física. Los pasos necesarios para crear un archivo que pueda ser programado en dicha memoria son:

1. Escritura del código fuente: Creación del código fuente en cualquier editor de texto utilizando un lenguaje de alto nivel como C o C++.

2. Compilación: Utilizando un compilador (GCC en nuestro caso) se crea un objeto que contiene las instrucciones en lenguaje de máquina del procesador a utilizar (uno diferente al que realiza la compilación que normalmente es de la familia x86); en este punto el compilador solo busca en los encabezados (headers) la definición de una determinada función, esto es, la forma en que debe ser utilizada, el tipo de datos y el número de parámetros con que debe ser invocada, por ejemplo, la función printf esta declarada en el archivo stdio.h como: int printf (const char *template, ...). Esta declaración es utilizada por el compilador para verificar el correcto uso de esta función.

3. Enlazado: En esta etapa se realizan dos tareas:

a) Se enlazan los archivos tipo objeto del proyecto, junto con librerías precompiladas para el procesador de la plataforma, si una determinada función no es definida en ninguna de estas librerías, el enlazador generará un error y no se generará el ejecutable.

b) Se definen las posiciónes físicas de las secciones que componen el archivo ejecutable (tipo ELF), esto se realiza a través de un link de enlazado en el que se define de forma explícita su localización.

4. Extracción del archivo de programación En algunas aplicaciones (cuando no se cuenta con un sistema operativo) es necesario extraer las secciones del ejecutable que residen en los medios de almacenamiento no volátil, que como veremos más adelante representan el conjunto de instrucciones que debe ejecutar el procesador de la plataforma y las constantes del programa. Esto se realiza con la herramiento objcopy, la cual, nos permite generar archivos en la mayoría de los formatos soportados por los programadores de memorias y procesadores, como S19 e Intel Hex.

5. Descarga del programa a la plataforma. Dependiendo de la plataforma existen varios métodos para descargar el archivo de programación a la memoria de la plataforma:

a) Utilizando un loader: El loader es una aplicación que reside en un medio de almacenamiento no volátil y permite la descarga de archivos utilizando el puerto serie, USB, o una interfaz de red.

b) Utilizando el puerto JTAG: El puerto JTAG (Joint Test Action Group) proporciona una interfaz capaz de controlar los registros internos del procesador, y de esta forma, acceder a las memorias de la plataforma y ejecutar un programa residente en una determinada posición de memoria.

6. Depuración Una vez se descarga la aplicación a la plataforma es necesario someterla a una serie de pruebas con el fín de probar su correcto funcionamiento. Esto se puede realizar con el depurador GNU (GDB) y una interfaz de comunicación que puede ser un puerto serie, USB o un adaptador de red.

2.5.3. El formato ELF

El formato ELF (Executable and Linkable Format) Es un stándard para objetos, librerías y ejecutables y es el formato que genera las herramientas GNU. Como puede verse en la figura 2.7 está compuesto por varias secciones (link view) o segmentos (execution view). Si un programador está interesado en obtener información de secciones sobre tablas de símbolos, código ejecutable específico o información de enlazado dinámico debe utilizar link view. Pero si busca información sobre segmentos, como por ejemplo, la localización de los segmentos text o data debe utilizar execution view. El encabezado describe el layout del archivo, proporcionando información de la forma de acceder a las secciones [9].

Las secciones pueden almacenar código ejecutable, datos, información de enlazado dinámico, datos de depuración, tablas de símbolos,comentarios, tablas de strings, y notas. Las secciones más importantes son las siguientes:

.bss Datos no inicializados. (RAM) .comment Información de la versión. .data y .data1 Datos inicializados. (RAM) .debug Información para depuración simbólica. .dynamic Información sobre enlace dinámico .dynstr Strings necesarios para el enlacedinámico .dynsym Tabla de símbolos utilizada para enlace dinámico. .fini Código de terminación de proceso. .init Código de inicialización de proceso. .line Información de número de línea para depuración simbólica. .rodata y .rodta1 Datos de solo-lectura (ROM) .shstrtab Nombres de secciones. .symtab Tabla de símbolos. .text Instrucciones ejecutables (ROM)

Para aclarar un poco este concepto, escribamos una aplicación sencilla:

#i n c l u d e <s t d i o .h>
i n t g l o b a l ;
i n t g l o b a l 1 = 1 ;
i n t main ( void )

{

i n t i ;  / / V a r i a b l e no i n i c i a l i z a d a
i n t j = 2 ;  / / V a r i a b l e i n i c i a l i z a d a
f o r ( i =0; i <10; i ++){
p r i n t f ( ”P r i n t i n g %d\n” , i∗ j ) ;  / / C a r a c t e r e s c o n s t a n t e s
j = j + 1 ;
g l o b a l = i ;
g l o b a l 1 = i+ j ;

}

return 0 ;

}

Generemos el objeto compilándolo con el siguiente comando: arm-none-eabi-gcc -c hello.c Examinemos que tipo de secciones tiene este ejecutable arm-none-eabi-readelf -S hello.o

S e c t i o n Headers :
[Nr] Name  Type  Addr  Off  S i z e ES Flg Lk I n f Al
[ 0]  NULL  00000000 000000 000000 00  0 0 0
[ 1] . t e x t  PROGBITS  00000000 000034 00009c 00 AX 0 0 4
[ 2] . r e l . t e x t  REL  00000000 000484 000020 08  9 1 4
[ 3] . d a t a  PROGBITS  00000000 0000d0 000004 00 WA 0 0 4
[ 4] . b s s  NOBITS  00000000 0000d4 000000 00 WA 0 0 1
[ 5] . r o d a t a  PROGBITS  00000000 0000d4 000010 00 A 0 0 4
[ 6] . comment  PROGBITS  00000000 0000e4 00004d 00  0 0 1
[ 7] .ARM. a t t r i b u t e s ARM ATTRIBUTES 00000000 000131 00002e 00  0 0 1
[ 8] . s h s t r t a b  STRTAB  00000000 00015 f 000051 00  0 0 1
[ 9] . symtab  SYMTAB  00000000 000368 0000 f0 10  10 11 4

[ 1 0 ] . s t r t a b  STRTAB  00000000 000458 00002b 00  0 0 1
Key t o F l a g s :
W ( w r i t e ) , A ( a l l o c ) , X ( e x e c u t e ) , M ( merge ) , S ( s t r i n g s )
I ( i n f o ) , L ( l i n k o r d e r ) , G ( group ) , x (unknown)
O ( e x t r a OS p r o c e s s i n g r e q u i r e d ) o (OS s p e c i f i c ) , p ( p r o c e s s o r s p e c i f i c )

La sección .text, como se dijo anteriormente contiene las instrucciones ejecutables, por esta razón se marca como ejecutable “X” en la columna Flg. Es posible ver las instrucciones que se ejecutan en esta sección:

arm-none-eabi-objdump -d -j .text hello.o

00000000 <main>:
0 :  e92d4800  stmdb sp ! , {fp , l r }
4 :  e28db004  add  fp , sp , #4  ; 0x4
8 :  e24dd008  sub  sp , sp , #8  ; 0x8
c :  e3a03002  mov  r3 , #2 ; 0x2
1 0 :  e50b3008  s t r  r3 , [ fp , #−8]
1 4 :  e3a03000  mov  r3 , #0 ; 0x0
1 8 :  e50b300c  s t r  r3 , [ fp , #−12]
1c :  ea000013  b  70 <main+0x70>
2 0 :  e51b200c  l d r  r2 , [ fp , #−12]
2 4 :  e51b3008  l d r  r3 , [ fp , #−8]
2 8 :  e0030392  mul  r3 , r2 , r3
2c :  e59f005c  l d r  r0 , [pc , #92]  ; 90 <.t e x t +0x90>
3 0 :  e1a01003  mov  r1 , r3
3 4 :  e b f f f f f e  b l  0 <p r i n t f >
3 8 :  e51b3008  l d r  r3 , [ fp , #−8]
3c :  e2833001  add  r3 , r3 , #1  ; 0x1
4 0 :  e50b3008  s t r  r3 , [ fp , #−8]
4 4 :  e59f2048  l d r  r2 , [pc , #72]  ; 94 <.t e x t +0x94>
4 8 :  e51b300c  l d r  r3 , [ fp , #−12]
4c :  e5823000  s t r  r3 , [ r2 ]
5 0 :  e51b200c  l d r  r2 , [ fp , #−12]
5 4 :  e51b3008  l d r  r3 , [ fp , #−8]
5 8 :  e0822003  add  r2 , r2 , r3
5c :  e59f3034  l d r  r3 , [pc , #52]  ; 98 <.t e x t +0x98>
6 0 :  e5832000  s t r  r2 , [ r3 ]
6 4 :  e51b300c  l d r  r3 , [ fp , #−12]
6 8 :  e2833001  add  r3 , r3 , #1  ; 0x1
6c :  e50b300c  s t r  r3 , [ fp , #−12]
7 0 :  e51b300c  l d r  r3 , [ fp , #−12]
7 4 :  e3530009  cmp  r3 , #9 ; 0x9
7 8 :  d a f f f f e 8  b l e  20 <main+0x20>
7c :  e3a03000  mov  r3 , #0 ; 0x0
8 0 :  e1a00003  mov  r0 , r3
8 4 :  e24bd004  sub  sp , fp , #4  ; 0x4
8 8 :  e8bd4800  ldmia  sp ! , {fp , l r }
8c :  e 1 2 f f f 1 e  bx  l r

La sección .data mantiene las variables inicializadas, y contiene:

arm-none-eabi-objdump -d -j .data hello.o

00000000 <g l o b a l 1 >:
0 :  01 00 00 00

Como vemos, la sección .data contiene únicamente el valor de inicialización de la variable global 1 (1) y no muestra informacióón acerca de la variable j, esto se debe a que la información está en el stack del proceso. Si observamos el contenido de la sección .text observamos que esta variable es asignada en tiempo de ejecución, en la línea 0c:

0c :  e3a03002  mov  r3 , #2 ; 0x2
1 0 :  e50b3008  s t r  r3 , [ fp , #−8]

se ve la asignación de esta variable.

La sección .bss mantiene la información de las variables no incializadas: arm-none-eabi-objdump -d -j .bss hello

000145c4 <g l o b a l >:
145c4 :  00000000

En Linux todas las variables no inicializadas, se inicializadan en cero.

La sección .rodata mantiene los datos que no cambian durante la ejecución del programa, es decir, de solo lectura, si examinamos esta sección obtenemos:

hexdump -C hello.o — grep -i 000000d0 (la sección .rodata comienza en la posición de memoria 0xd4)

000000d0 01 00 00 00 50 72 69 6e 74 69 6e 67 20 25 64 0a | …. P r i n t i n g %d . |
000000e0 00 00 00 00 00 47 43 43 3a 20 28 43 6f 64 65 53 | . . . . .GCC: (CodeS |

Observamos que en el archivo se almacena la cadena de caracteres Printing %d n la cual no se modifica durante la ejecución del programa.

2.5.4. Herramienta de compilación make

Como pudo verse en la sección es necesario realizar una serie de pasos para poder descargar una aplicación a una plataforma embebida. Debido a que las herramientas GNU solo poseen entrada por consola, es necesario esribir una serie de comandos cada vez que se realiza un cambio en el código fuente, lo cual resulta poco práctico. Para realizar este proceso de forma automática se creó la herramienta make, la cual recibe como entrada un archivo que normalmente tiene el nombre Makefile o makefile y determina que archivos han sido modificados desde la última compilación y ejecuta los comandos necesarios para recompilarlos. Un ejemplo de este tipo de archivo se muestra a continuación:

1 SHELL = /b i n /sh

2

3 b a s e t o o l s d i r = /home/a t 9 1 /gcc −3.4.5−g l i b c − 2 . 3 . 6 /arm−s o f t f l o a t −l i n u x−gnu
4 b i n d i r = ${ b a s e t o o l s d i r } /b i n
5 l i b d i r = ${ b a s e t o o l s d i r } /l i b /gcc /arm−s o f t f l o a t −l i n u x−gnu / 3 . 4 . 5

6

7 CC  = arm−s o f t f l o a t −l i n u x−gnu−gcc
8 AS  = arm−s o f t f l o a t −l i n u x−gnu−as
9 LD  = arm−s o f t f l o a t −l i n u x−gnu−l d
10 OBJCOPY = arm−s o f t f l o a t −l i n u x−gnu−objcopy

11

12 CFLAGS =−mcpu=arm920t −I . −Wall
13 LDFLAGS =−L${ l i b d i r } −l gcc

14

15 OBJS = \
16  main .o  \
17  d e b u g i o .o  \
18  a t 9 1 r m 9 2 0 0 l o w l e v e l .o \
19  p s t r i n g .o

20

21 ASFILES = a r m i n i t .o

22

23 LIBS=${ l i b d i r } /

24

25 a l l : h e l l o w o r l d

26

27 h e l l o w o r l d : ${OBJS} ${ASFILES} ${LIBS}
28  ${LD} −e 0 −o h e l l o w o r l d . e l f −T l i n k e r . c f g ${ASFILES} ${OBJS} ${LDFLAGS}
29  ${OBJCOPY} −O b i n a r y h e l l o w o r l d . e l f h e l l o w o r l d . b i n

30

31 c l e a n :
32  rm −f ∗.o ∗˜ h e l l o w o r l d . ∗

34 PREPROCESS. c = $(CC) $(CPPFLAGS) $(TARGET ARCH) −E −Wp,−C,−dD,−dI

35

36 %. pp : %. c FORCE
37  $(PREPROCESS. c ) $< > $@

En las líneas 3-5 se definen algunas variables globales que serán utilizadas a lo largo del archivo; en las líneas 7 - 10 se definen las herramientas de compilación a utilizar, específicamente el compilador C (CC), el ensamblador (AS), el enlazador (LD) y la utilidad objcopy. A partir de la línea 15 se definen los objetos que forman parte del proyecto, en este caso: main.o, debug io.o, at91rm9200 lowlevel.o y p string.o; en la línea 21 se definen los archivos en assembler que contiene el proyecto, para este ejemplo arm init.o. Las líneas 12 y 13 definen dos variables especiales que se pasan directamente al compilador C (CFLAGS) y al enlazador (LDFLAGS) y definen parámetros de comportamiento de estas herramientas.

CFLAGS =−mcpu=arm920t −I . −Wall

El parámetro -mcpu le indica al compilador C para arquitecturas ARM que utilice la familia arm920; el parámetro -I le indica un directorio donde puede buscar los encabezados, en este caso el caracter ”.”le indica que busque en el mismo sitio donde se encuentran los archivos fuente; el parámetro -Wall le indica que imprima todos los mensajes de errores y advertencias.

LDFLAGS =−L${ l i b d i r } −l gcc

El parámetro -L le indica al enlazador la ruta del directorio donde se encuentran las librerías, en este ejemplo apunta a la variable textitlibdir que se encuentra declarado como $basetoolsdir/lib/gcc/arm-softfloat-linux-gnu/3.4.5; el parámetro -l le indica al enlazador que debe utilizar la librería gcc que se encuentra en el directorio definido previamente. En realidad el archivo de la librería tienen el nombre libgcc.a, pero como todas las librerías tienen el nombre libXXXX.a se eliminan el encabezado y la extensión del archivo.

En las líneas 25, 27 y 31 aparecen unas etiquetas de la forma: nombre: estos labels permiten ejecutar de forma independiente el conjunto de instrucciones asociadas a ellas, por ejemplo, si se ejecuta: make clean

make ejecutará el comando:

rm -f *.o * hello world.*

Observemos los comandos asociados a la etiqueta hello world: En la misma línea aparecen $OBJS $ASFILES $LIBS esto le indica a la herramienta make que antes de ejecutar los comandos asociados a este label, debe realizar las acciones necesarias para generar $OBJS $ASFILES $LIBS o lo que es lo mismo: main.o, debug io.o, at91rm9200 lowlevel.o, p string.o, arm init.o y libgcc.a. Para esto, make tiene predefinidas una serie de reglas para compilar los archivos .c la regla es de la forma:

. c .o :
$(CC) $(CFLAGS) −c $<
. c :
$(CC) $(CFLAGS) $@ . c $(LDFLAGS) −o $@

Lo cual le indica a la herramienta make que para generar un archivo .o a partir de uno .c es necesario ejecutar $(CC) $(CFLAGS) -c $¡; de aqui la importancia de definir bien la variable de entorno CC cuando trabajamos con compiladores cruzados^{12}. Hasta este punto al ejecutar el comando: make hello world, make realizaría las siguientes operaciones:

arm−s o f t f l o a t −l i n u x−gnu−gcc −mcpu=arm920t −I . −Wall −c −o main .o main . c
arm−s o f t f l o a t −l i n u x−gnu−gcc −mcpu=arm920t −I . −Wall −c −o d e b u g i o .o d e b u g i o . c
arm−s o f t f l o a t −l i n u x−gnu−gcc −mcpu=arm920t −I . −Wall −c −o a t 9 1 r m 9 2 0 0 l o w l e v e l .o a t 9 1 r m 9 2 0 0 l o w l e v e l . c
arm−s o f t f l o a t −l i n u x−gnu−gcc −mcpu=arm920t −I . −Wall −c −o p s t r i n g .o p s t r i n g . c
arm−s o f t f l o a t −l i n u x−gnu−as  −o a r m i n i t .o a r m i n i t . s

En las líneas 28 se realiza el proceso de enlazado; al enlazador se le pasan los parámetros:

12Un compilador cruzado genera código para una plataforma diferente en la que se está ejecutando, por ejemplo, genera ejecutables para ARM pero se ejecuta en un x86 -e 0: Punto de entrada , utiliza la dirección de memoria 0 como punto de entrada.

-o hello world.elf: Nombre del archivo de salida hello world

-T linker.cfg: Utilice el archivo de enlace linker.cfg

$ASFILES $OBJS $LDFLAGS: Lista de objetos y librerías para crear el ejecutable.

En la línea 29 se utiliza la herramienta objcopy para generar un archivo binario (-O binary) con la información necesaria para cargar en una memoria no volátil.

Archivo de enlace

Como vimos anteriormente, el enlazador o linker es el encargado de agrupar todos los archivos objeto .o, y las librerías necesarias para crear el ejecutable, adicionalmente, permite definir donde serán ubicados los diferentes segmentos del archivo ELF en un archivo de enlace linker script. De esta forma podemos ajustar el ejecutable a plataformas con diferentes configuraciones de memoria, lo que proporciona un grado mayor de flexibilidaad de la cadena de herramientas GNU. Cuando se dispone de un sistema operativo como Linux no es necesario definir este archivo, ya que el sistema operativo se encarga del manejo de las diferentes secciones, sin embargo, es necesario tenerlo presente ya que como veremos más adelante existe un momento en el que el sistema operativo no ha sido cargado en la plataforma y las aplicaciones que se ejecuten deben proporcionar esta información. A continuación se muestra un ejemplo de este archivo:

/ ∗ i d e n t i f y t h e Entry P o i n t ( v e c r e s e t i s d e f i n e d i n f i l e c r t . s ) ∗ /
ENTRY( v e c r e s e t )
/ ∗ s p e c i f y t h e memory areas ∗ /

MEMORY {

f l a s h : ORIGIN = 0 ,  LENGTH = 256K  / ∗ FLASH EPROM  ∗ /
ram  : ORIGIN = 0x00200000 , LENGTH = 64K  / ∗ s t a t i c RAM area  ∗ /

}

/ ∗ d e f i n e a g l o b a l symbol s t a c k e n d ∗ /
s t a c k e n d = 0x20FFFC ;
/ ∗ now d e f i n e t h e o u t p u t s e c t i o n s ∗ /

SECTIONS {

. = 0 ;  / ∗ s e t l o c a t i o n c o u n t e r t o a d d r e s s z e r o ∗ /
. t e x t :  / ∗ c o l l e c t a l l s e c t i o n s t h a t s h o u l d go i n t o FLASH a f t e r s t a r t u p ∗ /

{

∗ ( . t e x t )  / ∗ a l l . t e x t s e c t i o n s ( code ) ∗ /
∗ ( . r o d a t a )  / ∗ a l l . r o d a t a s e c t i o n s ( c o n s t a n t s , s t r i n g s , e t c . ) ∗ /
∗ ( . r o d a t a ∗)  / ∗ a l l . r o d a t a ∗ s e c t i o n s ( c o n s t a n t s , s t r i n g s , e t c . ) ∗ /
∗ ( . g l u e 7 )  / ∗ a l l . g l u e 7 s e c t i o n s ( no i d e a what t h e s e are ) ∗ /
∗ ( . g l u e 7 t )  / ∗ a l l . g l u e 7 t s e c t i o n s ( no i d e a what t h e s e are ) ∗ /
e t e x t = . ;  / ∗ d e f i n e a g l o b a l symbol e t e x t j u s t a f t e r t h e l a s t code b y t e ∗ /
} >f l a s h  / ∗ p u t a l l t h e above i n t o FLASH ∗ /
. d a t a :  / ∗ c o l l e c t a l l i n i t i a l i z e d . data s e c t i o n s t h a t go i n t o RAM ∗ /

{

d a t a = . ;  / ∗ c r e a t e a g l o b a l symbol marking t h e s t a r t o f t h e . data s e c t i o n ∗ /
∗ ( . d a t a )  / ∗ a l l . data s e c t i o n s ∗ /
e d a t a = . ;  / ∗ d e f i n e a g l o b a l symbol marking t h e end o f t h e . data s e c t i o n ∗ /
} >ram AT >f l a s h / ∗ p u t a l l t h e above i n t o RAM ( b u t load t h e LMA i n i t i a l i z e r copy i n t o FLASH)

∗ /

. b s s :  / ∗ c o l l e c t a l l u n i n i t i a l i z e d . b s s s e c t i o n s t h a t go i n t o RAM ∗ /

{

b s s s t a r t = . ; / ∗ d e f i n e a g l o b a l symbol marking t h e s t a r t o f t h e . b s s s e c t i o n ∗ /
∗ ( . b s s )  / ∗ a l l . b s s s e c t i o n s ∗ /
} >ram  / ∗ p u t a l l t h e above i n RAM ( i t w i l l be c l e a r e d i n t h e s t a r t u p code ∗ /
. = ALIGN( 4 ) ;  / ∗ advance l o c a t i o n c o u n t e r t o t h e n e x t 32−b i t boundary ∗ /
b s s e n d = . ;  / ∗ d e f i n e a g l o b a l symbol marking t h e end o f t h e . b s s s e c t i o n ∗ /

}

end = . ;  / ∗ d e f i n e a g l o b a l symbol marking t h e end o f a p p l i c a t i o n RAM ∗ /

En las primeras líneas del archivo aparece la declaración de las memorias de la plataforma, en este ejemplo tenemos una memoria RAM de 64kB que comienza en la posición de memoria 0x00200000 y una memoria flash de 256k que comienza en la posición 0x0. A continuacion se definen las secciones y el lugar donde serán almacenadas; En este caso, las secciones .text (código ejecutable) y .rodata (datos de solo lectura) se almacenan en una memoria no volátil la flash. Cuando el sistema sea energizado el procesador ejecutará el código almacenado en su memoria no volátil. Las secciones .data (variables inicializadas) y .bss (variables no inicializadas) se almacenarán en la memoria volátil RAM, ya que el acceso a las memorias no volátiles son más lentas y tienen ciclos de lectura/escritura finitos.

Algunos desarrolladores prefieren almacenar y ejecutar sus aplicaciones en las memorias volátiles durante la etapa de desarrollo, debido a que la programación de las memorias no volátiles toman mucho más tiempo. Obviamente una vez finalizada la etapa de desarrollo las aplicaciones deben ser almacenadas en memorias no volátiles.

Figura 2.6: Tendencia del mercado de procesadores para sistemas embebidos. Fuente:[7]

Figura 2.7: Formato ELF

Bibliografía

[1] Aleph 1. Building the Toolchain. http://www.aleph1.co.uk/node/279.

[2] Wikipedia. Wikipedia, the free encyclopedia. http://en.wikipedia.org/.

[3] C. Lanfear, S. Balacco, and M. Volckmann. The 2005 Embedded Software Strategic Market Intelligence Program. Venture Development Corporation http://www.vdc-corp.com, August 2005.

[4] J. Turley. Embedded systems survey: Operating systems up for grabs. Embedded Systems Programming, May 2004.

[5] Venture Development Corp. Small teams dominate embedded software development. http://www.linuxdevices.com/articles/AT7019328497.html, 1 June 2006.

[6] Bill Gatliff. Porting and Using Newlib in Embedded Systems. http://venus.billgatliff.com/node/3.

[7] Linuxdevices. Embedded Linux market snapshot, 2005. http://www.linuxdevices.com, 4 May 2005.

[8] Dan Kegel. Building and Testing gcc/glibc cross toolchains. http://www.kegel.com/crosstool/, 20 February 2006.

[9] Michael L. Haungs. The Executable and Linking Format (ELF). http://www.cs.ucdavis.edu/ haungs/paper/node1.html, 21 September 1998.