1. ¿Qué cadena de herramientas?
En incrustado, gcc es el conjunto de herramientas más prominente en uso. Entre las distribuciones de las herramientas principales de gcc, «Linaro» se utilizará como referencia mucho en esta serie. Linaro soportar Linux y Android. Sus parches muy probablemente serán adoptadas por la corriente. Su exclusivo soporte para ARM lo convierten en un líder en la cadena de herramientas ARM, con el apoyo inmediato para los nuevos tableros de chips ARM / dev. Así que creo Linaro es una buena referencia para mi cubietruck A20 Cortex-A7 basado. Pero vamos a construir la cadena de herramienta directamente desde el más reciente fuente de aguas arriba en vez de desde la fuente Linaro, ya que la mayoría de los parches de Linaro se han portado de nuevo a la corriente. Si las condiciones lo exigen el uso de Linaro distribución específica debido a los parches no-portado hacia atrás, vamos a utilizar Linaro distribución directa.
2. Independientes contra entorno C Alojado en GCC
Según definición de la Comisión de Normas de C, hay dos modos de compilador C y el tiempo de ejecución, a saber, «independiente» y «conducido». . Estos dos modos sólo especifican el grado de la biblioteca de soporte, es decir, c biblioteca
Para independientes, estas cabeceras son obligatorios en C99:
<float.h>
, <limits.h>
, <stdarg.h>,
<iso646.h>, <stdbool.h>
,<stdint.h>
En C11, se añaden dos cabeceras extra: (gcc no implementa C11 completamente todavía.)
Todas estas cabeceras son sólo const y definiciones de tipo. No hay sistema o sistema operativo cosas dependen de ellos. kernel Linux, y aplicación independiente integrado, gestor de arranque todas las vidas en el medio ambiente "independiente".
En "conducido" medio ambiente, la aplicación se ejecuta con la ayuda de una pila de servicios de la plataforma Un diagrama aclarar tales soportes:
entorno independiente:
Medio ambiente Hosted:
http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc / standards.html # Normas
¿Por qué nos molestamos con "independiente" y "conducido" cosas Porque:?.
En un mundo integrado, independiente es una forma canónica de la vida. ¡Tienes que lidiar con el gestor de arranque, el kernel, la biblioteca c directamente.
b. Construir cadena de herramientas GCC, conocimiento profundo de estos dos modos le ayudará a entender cómo bootstraps gcc sí mismo. Esto es muy importante cuando se intenta entiende cómo funciona compilador cruzado.
3. Alojado
Aquí está nuestro "hello.c". Se trabaja con la ayuda de "entorno alojado."
# include
int main (int argc, char * argv [])
{
printf (" hello world! n ");
return 0;
}
Desde que usamos "stdio.h", y no es parte de las cabeceras de entorno "independiente", estamos programando en entorno alojado. La función "printf" es proporcionado por la biblioteca estándar c. GCC por defecto "organizadas" modo también. Así que veamos lo Códigos generan cuando se compila este programa. Recuérdese por favor este programa se ejecuta en mi PC 7 debian linux. />
gcc-S hello.c-o hello.s
cat hello.s
# file este conjunto se genera a partir de "hello.c"
. archivo " hola.c "
# asigne una sección llamada" Rodata "- leer sólo los datos
# de colocar nuestro constante de cadena" hello world font-family: Courier New, Courier, "
. sección. Rodata span>
. LC0:
cadena "
# aquí es la sección. "texto" para mantener la instrucción ejecutable
texto
# declare" principal "como" función global ", por lo que podría ser visto por
# otros módulos / archivos mientras vinculado con la biblioteca estándar de C
GLOBL principal
escribe principal, la función @
# en entorno AMD64, llamadas a funciones siguen convención de llamada estricta Se llama "interfaz binaria de aplicación", es decir, ABI La especificación para AMD64 ABI está aquí:..
# http://www.x86-64.org/documentation/abi.pdf
# en nuestro ejemplo,
principal:.
LFB0:
construcción # stack frame siguiente API AMD64.
# cfi significa" llamar a información de la trama ". Es una directiva de extensión GCC gcc lo utilizan para descansar fotograma de la llamada anidada cuando se produce una excepción
cfi_startproc
# primer salvamento llamando registro base frame% RBP en pila
pushq% RBP
. cfi_def_cfa_offset 16
cfi_offset 6, -16
# guarda puntero de pila% rsp actual en% RBP, el registro de base de la chimenea
; movq% rsp, RBP%
;. cfi_def_cfa_register 6
# asigna 16 bytes en el marco de pila para almacenar variables temporales
subq $ 16,% rsp
# AMD64 ABI utilice"% RDI, rsi%,% rdx, rcx%,% r8 y r9% "para aprobar los parámetros de llamada de función
# de int main (int argc, char * argv []), "% edi" es "argc", y " rsi "es" argv "
# ya que vamos a llamar a otras funciones en "principal", "% edi,% rsi" conseguirá invalida durante
# llamada función anidada, por lo que los almacena en la pila de lugares temporales en primer lugar, en caso de que todavía # # Necesitamos acceder a ellos después de las llamadas funciones anidadas
; movl% edi, -4 (% RBP)
movq% rsi, -16 (% RBP)
# LC0 . es la dirección de la cadena "Hello World!" Cambiamos en% edi pasar como la
# primer parámetro para llamar a la función" puts "
. # pone es más que otra función en la biblioteca estándar de C Aquí está su prototipo:
#" int puts (const char * s); "
movl $ . LC0,% edi
llamada puts
# ahora" hola mundo "quedó impreso en la salida estándar de" puts ", es el momento de volver de" principal "
# de acuerdo con ABI AMD64, el valor devuelto de la función se debe colocar dentro de"% eax "
movl $ 0,% eax
# "salir" se ajustará fun marco de llamada para que podamos devolver la forma función de llamada
#" licencia "es equivalente a" movq% RBP,% rsp; POPQ% RBP "
dejar
. cfi_def_cfa 7, 8
# ahora volver de main ();
ret
cfi_endproc
LFE0:
# directiva tamaño calculará el tamaño en bytes de la función" principal fuente-familia "
#".-principal "significa" current_address - dirección del principal font-family: Courier New, Courier, "
Tamaño principal,-principal.
# éstos son general "comentarios como" la información generada por el ensamblador de GNU.
ident GCC ": (Debian 4.7. 2-5) 4.7.2 "
. sección. note.GNU-stack, "", @ progbits
Ahora podemos ver la concepto de ABI, que generalmente es la función de la convención de llamada en un hardware específico + entorno de sistema operativo y cómo se pasan los parámetros de la función durante la llamada de función. Podemos ver también que "printf ()" se aplica realmente por "puts ()" en la biblioteca c. Pasemos.
gcc-c-o hello.s hello.o
nm hello.o
0000000000000000 T principal
U puts
objdump - h hello.o