Sei sulla pagina 1di 33

Ampliación de Sistemas Operativos

Introducción a la Programación de Sistemas


Compilación y enlazado

ASO
Agenda

1 Compilación y enlazado

2 Herramientas de compilación

ASO 2/26
Agenda

1 Compilación y enlazado

2 Herramientas de compilación

ASO 3/26
Compilación y Enlazado

Código fuente C
cc1 fun.c
fun.o
int fun( )
Preprocesador { cc1+as .text
$\ldots$ ejecutable
return local; .data
} .text
Código C modificado gcc
.text
ld
main.c
Compilador .data
main.o
int main( ) .data
{
$\ldots$ cc1+as .text
Código Ensamblador fun();
$\ldots$ .data
as return 0;
}

Ensamblador
Otros ficheros
objeto
Código Objeto Reubicable Bibliotecas
Estáticas

ld
Enlazador

Ejecutable

ASO 4/26
Compilación y Enlazado

Código fuente C
cc1 fun.c
fun.o
int fun( )
Preprocesador { cc1+as .text
$\ldots$ ejecutable
return local; .data
} .text
Código C modificado gcc
.text
ld
main.c
Compilador .data
main.o
int main( ) .data
{
$\ldots$ cc1+as .text
Código Ensamblador fun();
$\ldots$ .data
as return 0;
}

Ensamblador
Otros ficheros
objeto
Código Objeto Reubicable Bibliotecas
Estáticas

ld
Enlazador

Ejecutable

ASO 4/26
Compilación y Enlazado

Código fuente C
cc1 fun.c
fun.o
int fun( )
Preprocesador { cc1+as .text
$\ldots$ ejecutable
return local; .data
} .text
Código C modificado gcc
.text
ld
main.c
Compilador .data
main.o
int main( ) .data
{
$\ldots$ cc1+as .text
Código Ensamblador fun();
$\ldots$ .data
as return 0;
}

Ensamblador
Otros ficheros
objeto
Código Objeto Reubicable Bibliotecas
Estáticas

ld
Enlazador

Ejecutable

ASO 4/26
Compilación y Enlazado

Código fuente C
cc1 fun.c
fun.o
int fun( )
Preprocesador { cc1+as .text
$\ldots$ ejecutable
return local; .data
} .text
Código C modificado gcc
.text
ld
main.c
Compilador .data
main.o
int main( ) .data
{
$\ldots$ cc1+as .text
Código Ensamblador fun();
$\ldots$ .data
as return 0;
}

Ensamblador
Otros ficheros
objeto
Código Objeto Reubicable Bibliotecas
Estáticas

ld
Enlazador

Ejecutable

ASO 4/26
En resumen

De la descripción anterior concluimos:


El compilador/ensamblador generan el código máquina reubicable
Algunas instrucciones pueden tener alguna parte incompleta
Algunas entradas de la sección de texto pueden estar incompletas
La tabla de sı́mbolos del fichero objeto guarda la información de que
entradas hay que relocalizar (completar)
En la etapa de enlazado:
se conforma el mapa de memoria (fijando la posición de cada sección)
se resuelven los sı́mbolos
se relocalizan las partes incompletas de la sección de texto

ASO 5/26
Veamos un ejemplo (para ARM)

Hagamos a mano el trabajo que hace gcc .global start


Representaremos el contenido de cada sección .data
X: .word 5
como una tabla Y: .word 7
Indicaremos a la izquierda el offset .text
start: ldr r1, ???????
Representaremos conceptualmente las tablas ldr r2, ???????
cmp r1, r2
de sı́mbolos y relocalización blt L0
add r1, r1, #2
add r2, r2, #2
b L1
L0: sub r1, r1, #2
sub r2, r2, #2
L1: b .
.end

ASO 6/26
Secciones de Datos

Nuestro programa sólo tiene una sección de datos .data:


0 00000005
4 00000007

ASO 7/26
Tabla de sı́mbolos

El programa exporta un sı́mbolo: start


Define cuatro sı́mbolos locales (X, Y, L0 y L1).
La porción de la tabla de sı́mbolos que nos interesa serı́a:

Offset Sección Sı́mbolo


0 d X
4 d Y

ASO 8/26
Relocalización: Opción 1

Poner a 0 los offsets en los ldr Sección de código:


0x00 ldr r1,[PC, #0]
0x04 ldr r2,[PC, #0]
0x08 cmp r1, r2
0x0C blt 2
0x10 add r1, r1, #2
0x14 add r2, r2, #2
0x18 b 1
0x1C sub r1, r1, #2
0x20 sub r2, r2, #2
0x24 b -2

ASO 9/26
Relocalización: Opción 1

Poner a 0 los offsets en los ldr Sección de código:


0x00 ldr r1,[PC, #0]
Indicar al enlazador que debe modificar 0x04 ldr r2,[PC, #0]
los offsets 0x08 cmp r1, r2
0x0C blt 2
0x10 add r1, r1, #2
Tabla de relocalización de .text: 0x14 add r2, r2, #2
Off. Op Symb
0x18 b 1
0x00 Add Off. Rel. PC 8 bit X
0x1C sub r1, r1, #2
0x04 Add Off. Rel. PC 8 bit Y
0x20 sub r2, r2, #2
0x24 b -2

ASO 9/26
Relocalización: Opción 1

Poner a 0 los offsets en los ldr Sección de código:


0x00 ldr r1,[PC, #0]
Indicar al enlazador que debe modificar 0x04 ldr r2,[PC, #0]
los offsets 0x08 cmp r1, r2
0x0C blt 2
0x10 add r1, r1, #2
Tabla de relocalización de .text: 0x14 add r2, r2, #2
Off. Op Symb
0x18 b 1
0x00 Add Off. Rel. PC 8 bit X
0x1C sub r1, r1, #2
0x04 Add Off. Rel. PC 8 bit Y
0x20 sub r2, r2, #2
0x24 b -2

Problema: Esta operación de relocalización no está disponible

ASO 9/26
Relocalización: Opción 2

Escribir el offset de X e Y al final de Sección de código:


0x00 ldr r1,[PC, #40]
.text
0x04 ldr r1,[r1]
Indicar al enlazador que sume la 0x08 ldr r2,[PC, #36]
dirección de .data 0x0C ldr r2,[r2]
Añadir dos ldr que cargen esos valores 0x10 cmp r1, r2
en registro 0x14 blt 2
Usar esos registros para direccionar X e 0x18 add r1, r1, #2
Y 0x1C add r2, r2, #2
0x20 b 1
Tabla de relocalización de .text: 0x24 sub r1, r1, #2
Off. Op Symb
0x28 sub r2, r2, #2
0x30 R ARM ABS32 .data
0x2C b -2
0x34 R ARM ABS32 .data
0x30 00000000
0x34 00000004

ASO 10/26
Código definitivo
.global start
.data
X: .word 5
Y: .word 7
.text
start: ldr r1, =X
ldr r1, [r1]
ldr r2, =Y
ldr r2, [r2]
cmp r1, r2
blt L0
add r1, r1, #2
add r2, r2, #2
b L1
L0: sub r1, r1, #2
sub r2, r2, #2
L1: b .
.ltorg @Literales
.end

ASO 11/26
Código definitivo
.global start Compilamos
.data
X: .word 5
# make asm2.o
Y: .word 7
arm-none-eabi-gcc -mcpu=arm1176jzf-s -marm
.text
-mlittle-endian -O0 -g3 -x assembler-with-cpp
start: ldr r1, =X
-c -o asm2.o asm2.S
ldr r1, [r1]
# arm-none-eabi-objdump -D asm2.o
ldr r2, =Y
ldr r2, [r2]
cmp r1, r2
blt L0
add r1, r1, #2
add r2, r2, #2
b L1
L0: sub r1, r1, #2
sub r2, r2, #2
L1: b .
.ltorg @Literales
.end

ASO 11/26
Código definitivo
Desensamblado de la sección .text:
.global start 00000000 <start>:
.data 0: e59f1028 ldr r1, [pc, #40] ; 30 <L1+0x4>
X: .word 5 4: e5911000 ldr r1, [r1]
Y: .word 7 8: e59f2024 ldr r2, [pc, #36] ; 34 <L1+0x8>
.text c: e5922000 ldr r2, [r2]
start: ldr r1, =X 10: e1510002 cmp r1, r2
ldr r1, [r1] 14: ba000002 blt 24 <L0>
ldr r2, =Y 18: e2811002 add r1, r1, #2
ldr r2, [r2] 1c: e2822002 add r2, r2, #2
cmp r1, r2 20: ea000001 b 2c <L1>
blt L0
add r1, r1, #2 00000024 <L0>:
add r2, r2, #2 24: e2411002 sub r1, r1, #2
b L1 28: e2422002 sub r2, r2, #2
L0: sub r1, r1, #2
sub r2, r2, #2 0000002c <L1>:
L1: b . 2c: eafffffe b 2c <L1>
.ltorg @Literales 30: 00000000 .word 0x00000000
.end 34: 00000004 .word 0x00000004

Desensamblado de la sección .data:


00000000 <X>:
0: 00000005 andeq r0, r0, r5

00000004 <Y>:
4: 00000007 andeq r0, r0, r7
ASO 11/26
Estructura de un ejecutable ELF

ASO 12/26
Agenda

1 Compilación y enlazado

2 Herramientas de compilación

ASO 13/26
Flags habituales en gcc

-c
para generar el fichero objeto, no el ejecutable
-o
para indicar el nombre del fichero que se genere
-lnombre para enlazar con la librerı́a libnombre
-Lrutap ara indicar que se busquen librerı́as en ruta
-Iruta
para indicar que se busquen ficheros de cabecera en ruta
-Onpara indicar el nivel de optimización (entre 0 y 3)
-g
para incluir sı́mbolos de depuración en el ejecutable (y
poder depurar con gdb)
-pg para incluir información de instrumentación que permita
realizar profiling con gprof
-Wall para que se generen mensajes de warning en compilación
para todas las construcciones de código que se consideran
cuestionables
-Werror hace que los warnings se tomen como errores
https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html
ASO 14/26
Generación de una librerı́a estática

Colección de ficheros objetos almacenados en un único fichero (tar


de ficheros objeto)
Crear librerı́a estática

> ar cr libprueba.a fich1.o fich2.o

Con ese comando se crea la librerı́a estática libprueba.a


Ahora podremos enlazar nuestro código con esa librerı́a incluyendo
-lprueba en la lı́nea de compilación
Y el código de fich1.o y fich2.o queda incluido en el ejecutable
OJO: el enlazador busca el archivo (librerı́a) cuando lo ve en la lı́nea
de comando, por lo que suele ser habitual poner todas las librerı́as al
final
Enlazar con librerı́a estática

> gcc -o ejecutable -L. -lprueba main.o

ASO 15/26
Generación de una librerı́a dinámica

Similar a las estáticas, pues también contiene los ficheros objeto


Pero, al enlazar, el código NO se incluye en el ejecutable final
El código final contiene una referencia a la librerı́a dinámica
El código de la librerı́a se cargará en tiempo de ejecución
Crear librerı́a estática

> gcc -c -fPIC fich1.c fich2.c


> gcc -shared -fPIC -o libprueba.so fich1.o fich2.o

Cuestión
¿Para qué sirve el flag -fPIC?

El enlazado se realiza de forma similar, con el flag -l


Cuestiones
Si tenemos tanto versión estática como dinámica de una librerı́a,¿cuál se
usará en compilación?. ¿Para qué sirve la herramienta pkg-config?
ASO 16/26
Búsqueda de una librerı́a dinámica

Como el código de la librerı́a dinámica no está en el propio


ejecutable, debe buscarse en el momento de la ejecución

Cuestión
¿Es posible compilar dinámicamente una aplicación en una máquina y eje-
cutarla en otra?

La opción -L se usa para indicar dónde consultar la librerı́a durante


la compilación
LD LIBRARY PATH es una variable de entorno que podemos usar para
este propósito
Esto tiene doble efecto: también tiene el efecto del flag -L
Otra alternativa es usar -Wl,-rpath=ruta durante la compilación
para que se busque en ruta durante la ejecución

ASO 17/26
Búsqueda de una librerı́a dinámica

Busca información para responder a las siguientes preguntas:

Cuestión
¿Y si una librerı́a depende de otra?¿Es posible?¿Debemos indicar todas las
librerı́as en compilación?¿Y si hay dependencias circulares entre librerı́as?

Cuestión
¿Para qué sirve la herramienta ldd?¿Y ldconfig?

ASO 18/26
Carga dinámica explı́cita de código

En ocasiones interesa poder cargar código en tiempo de ejecución sin


un enlazado explı́cito previo (en compilación)
Por ejemplo para soportar plugins
Función de librerı́a:
void* dlopen(const char *path, int flags)
RTLD LAZY carga en el primer uso
RTLD NOW carga en el momento de la llamada
Devuelve un handle para posteriores acciones:

void* dlsym(void *handle, const char* symbol)


int dlinfo(void *handle, int request, void* info)
int dlclose(void *handle)

ASO 19/26
Makefile

Un makefile consiste en un conjunto de reglas y dependencias


Una dependencia tiene un objetivo (fichero que se creará) y un
conjunto de ficheros fuente de los que depende dicho objetivo
Una regla describe cómo crear el objetivo a partir de los ficheros de
los que depende
Se invoca mediante el comando make que. . .
Decide qué objetivo(s) se realizarán
Compara las fechas de los ficheros fuente para ver si fueron
modificados tras la última generación del objetivo
Decide qué reglas deben utilizarse para generar el objetivo
Generalmente, habrá reglas intermedias que deberán invocarse para
poder generar el objetivo final

Ejemplo

> ls
main.c foo.c faa.c tipos.h

ASO 20/26
Sintaxis de makefile: dependencias

Nuestra aplicación requiere (depende de) main.o, foo.o y faa.o


A su vez main.o depende de main.c y tipos.h
foo.o y faa.o también tienen dependencias, claro

Cuestión
¿Cómo se expresan las dependencias del ejemplo en el fichero makefile?

Más información:
https://www.gnu.org/software/make/manual/html_node/index.html

ASO 21/26
Sintaxis de makefile: reglas

Para cada dependencia podemos indicar qué acción llevar a cabo


para satisfacerla
Las acciones (reglas) se escriben en lı́neas que DEBEN comenzar por
un TABULADOR
make invoca un shell para ejecutar las reglas, y usa un nuevo shell
para cada regla

Cuestión
Si quisiéramos compilar manualmente, paso a paso, la aplicación del ejem-
plo, ¿qué comandos de compilación necesaitarı́amos?

Cuestión
Indica qué reglas hay que incluir en el Makefile del ejemplo para que se
genere el ejecutable

ASO 22/26
Sintaxis de makefile: macros
Podemos dar valor a una macro (similar a una variable) escribiendo
NOMBREMACRO=valor
Posteriormente podemos acceder al valor escribiendo
$(NOMBREMACRO) o $NOMBREMACRO
Las macros se pueden definir dentro del propio makefile o en la lı́nea
de comando cuando invocamos make:
make \CC=gcc"
Macros internas. Macros especiales predefinidas.
$? lista de pre-requisitos que más recientes que el objetivo
$@ nombre del objetivo actual
$< nombre de la primera dependencia
$ˆ lista de cada dependencia de la regla
$* nombre del pre-requisito actual, sin ningún sufijo (.c, .o. . . .)
Otros caracteres especiales
- indica a make que ignore los errores y continúe (por ejemplo, si
queremos crear un directorio y ya existe o borrar un fichero que no
existe)
@ indica a make que no imprima el comando en la salida estándar antes
de ejecutarlo
ASO 23/26
Sintaxis de makefile: múltiples objetivos

Podemos establecer varios objetivos, independientes o no, en el


makefile
Luego podemos referirnos a uno u otro desde la lı́nea de comando
usando
make <nombre objetivo>

ASO 24/26
Sintaxis de makefile: múltiples objetivos

¿Qué hace cada lı́nea de este extracto de makefile?

CC = gcc
INSTDIR = /usr/local/bin
CFLAGS = -g -Wall -ansi
all: miExec
...
.PHONY : clean
clean:
-rm main.o foo.o faa.o

install: miExec
@if [-d $(INSTDIR) ]; \
then \
cp miExec $(INSTDIR) && \
chmod a+x $(INSTDIR)\miExec && \
echo "Instalado en $(INSTDIR)" ; \
else \
echo "Error: $(INSTDIR) no existe"; false ; \
fi

ASO 25/26
Makefile: reglas implı́citas y reglas patrón

Existen numerosas reglas implı́citas para los cosas más habituales


Ejemplo: pasar de .c a .o
Asimismo, existe la posibilidad de usar patrones en función de los
sufijos de los ficheros
%.o : %.c
$(CC) $(CFLAGS) -I$(INCLUDE) -c $<
Otra alternativa es usar wildcard en la definición de variables
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
miApp: $(OBJ)
$(CC) -o $@ $^ $(LDFLAGS)

ASO 26/26

Potrebbero piacerti anche