Tabla de contenido
Este blog necesita usar el compilador vim. Si no está familiarizado con él, puede consultar el uso de vim en este blog.
1. Antecedentes
Para generar un archivo ejecutable a partir de un archivo fuente, debe pasar por el entorno de traducción del programa (traducir el archivo de texto del programa a un archivo binario que la máquina pueda reconocer), y el entorno de traducción se puede dividir en los siguientes cuatro pasos :
- Preprocesamiento (reemplazo de archivos de encabezado, compilación condicional, reemplazo de macros, eliminación de comentarios, etc.)
- compilar (generar lenguaje ensamblador)
- Ensamblar (genera un binario legible por máquina, no ejecutable, bin.obj)
- Vinculación (algún tipo de fusión de nuestros propios archivos .obj y archivos de biblioteca para generar archivos ejecutables)
Para obtener más información, consulte este entorno de programa de blog .
gcc/g++ puede ayudarnos a generar archivos ejecutables C/C++ bajo LInux y ejecutar cuatro pasos diferentes para el entorno de traducción a través de opciones.
gcc compila códigos de lenguaje C y g++ compila códigos de C++. Ambos se usan de la misma manera. A continuación se usa gcc como ejemplo.
2. Cómo generar gcc
Formato:gcc [选项] 要编译的文件 [选项] [目标文件]
primero creamos un archivo de prueba hello.c y usamos el editor vim para escribir el código
[YX@VM-16-5-centos lesson7]$ touch hello.c //创建hello.c文件
[YX@VM-16-5-centos lesson7]$ vim hello.c //使用vim编译器编译代码
Podemos usar gcc directamente para generar el archivo ejecutable del archivo de prueba y
luego ./a.out
ejecutar el archivo ejecutable para obtener el resultado de nuestro código,
pero cuando queremos obtener los archivos generados por él en las cuatro etapas diferentes del entorno de traducción, debemos ¿Cómo implementarlo?
1. Preprocesamiento (reemplazo de macros)
- Las funciones de preprocesamiento incluyen principalmente el reemplazo de macros, la inclusión de archivos, la compilación condicional y la eliminación de comentarios.
- Las directivas de preprocesamiento son líneas de código que comienzan con #.
- Ejemplo:
gcc -E hello.c
(Esta instrucción es para obtener directamente el contenido preprocesado e imprimirlo en el monitor, lo cual es inconveniente de ver y no se demostrará)- Ejemplo:
gcc -E hello.c -o hello.i
(Coloque el contenido preprocesado en el archivo .i)- Opción "-E", la función de esta opción es detener el proceso de compilación después de que se complete
gcc
el preprocesamiento.- La opción "-o" significa poner el resultado de la ejecución anterior en el siguiente archivo, y el archivo ".i" es el programa C original que ha sido preprocesado.
- Nota: El nombre del archivo se puede elegir a voluntad, esto no lo afecta, pero es mejor seguir las reglas y escribirlo como un archivo .i, lo mismo es cierto para los siguientes archivos
De acuerdo con las instrucciones anteriores, ejecutamos y generamos archivos preprocesados
Nota: los archivos .i no son archivos ejecutables, no podemos usarlos para ./hello.i
ejecutarlos, pero se pueden ver a través del editor vim
Finalmente se puede ver el contenido del archivo.
Ya sabemos cómo ver los archivos generados por el preprocesamiento, pero el caso anterior no demuestra completamente el efecto del preprocesamiento. Aquí primero modificamos el archivo de prueba y luego generamos el archivo .i para ver los resultados, y podemos sentir claramente el preprocesamiento El papel de lo siguiente:
- Para el archivo .i, podemos ver que tiene líneas 860, mientras que el archivo .c tiene solo líneas 24. El código redundante en el archivo .i es el código incluido en el archivo de encabezado
2. Compilar (generar ensamblado)
- En esta etapa, gcc primero debe verificar la estandarización del código, si hay errores gramaticales, etc., para determinar el trabajo real del código, y luego de que la verificación sea correcta, gcc traduce el código a lenguaje ensamblador.
- Los usuarios pueden usar la opción "-S" para ver, esta opción solo compila pero no ensambla y genera código ensamblador.
- Ejemplo:
gcc -S hello.c
(genere directamente el contenido compilado del archivo .c, muéstrelo en el monitor y vuelva a someterse al preprocesamiento, no se recomienda usar de esta manera)- Ejemplo:
gcc -S hello.i -o hello.s
(Esta instrucción es para generar un archivo .s a partir de un archivo .i)- Ejemplo:
gcc -S hello.c -o hello.s
(También es posible generar directamente un archivo .s a partir de un archivo .c y volver a someterse a un preprocesamiento)- Los archivos ".s" son programas compilados en C originales
Aquí generamos directamente el archivo .i en el archivo .s
Después de abrir, puede ver claramente el código ensamblador que genera
3. Ensamblaje (generación de código legible por máquina)
- La etapa de ensamblaje consiste en convertir el archivo ".s" generado en la etapa de compilación en un archivo de objeto.
- Aquí puede usar la opción "-c" para ver que el código de ensamblaje se ha convertido en el código de objeto binario de ".o"
- Ejemplo:
gcc -c hello.c
(igual que arriba, generar directamente datos compilados y mostrarlos en el monitor)- Ejemplo:
gcc -c hello.c -o hello.o
(igual que arriba, comenzando desde el archivo .c y reprocesando, compilando y ensamblando)- Ejemplo:
gcc -c hello.s -o hello.o
(del archivo compilado para generar el archivo ensamblado)
Aquí generaremos el archivo .o compilado a partir del archivo .s
Después de abrir, lo que vemos es que la máquina puede leer otros códigos, que no podemos entender
4. Enlace (generar archivo ejecutable o archivo de biblioteca)
- Después de una compilación exitosa, ingresa a la fase de vinculación.
- Ejemplo:
gcc hello.c -o hello
(Desde el archivo .c pasando por el entorno de traducción hasta el enlace)- Ejemplo:
gcc hello.o -o hello
(El archivo .o generado por ensamblaje genera un archivo vinculado)- El archivo vinculado es un archivo ejecutable, que se puede ejecutar directamente para
./hello
obtener el resultado del programa
Usamos archivos .o para generar archivos vinculados
Ver el contenido del ejecutable
código legible por máquina
pregunta
Dado que el contenido de los archivos generados después del ensamblaje y la vinculación son códigos reconocibles por máquina, ¿se pueden ejecutar los archivos generados después del ensamblaje?
Realicemos operaciones en él primero:
descubra que el archivo no tiene permisos de ejecución, agréguelo y ejecute:
Conclusión: Incluso si un archivo tiene un programa ejecutable, si no es un archivo ejecutable, no hay forma de ejecutarlo, y prueba que .o
el archivo no se puede ejecutar
Úselo para chmod -x hello.o
revocar sus permisos ejecutables.
3. Biblioteca de funciones
En la fase de vinculación, vinculamos el archivo de biblioteca, entonces, ¿qué es un archivo de biblioteca? Esto se explicará en detalle.
La razón por la que el programa C/C++ que escribimos puede ejecutarse en el compilador es porque nuestro compilador convierte el programa en un programa ejecutable a través del entorno de traducción y finalmente genera el resultado.
Además del código que escribimos, los programas que escribimos también llaman a las funciones proporcionadas en los archivos de encabezado. Por ejemplo, las funciones que usamos con frecuencia se declaran printf、scanf
en los archivos de encabezado stdio.h
. Estos archivos de encabezado se almacenan en /usr/include
directorios y subdirectorios en Linux. :
Dado que la declaración de estas funciones se coloca en el archivo de encabezado, ¿dónde se definen?
Sabemos que el entorno de traducción se divide en cuatro pasos, la función del último paso 链接
es combinar los archivos generados después del ensamblaje con los archivos de biblioteca, y las funciones declaradas en los archivos de encabezado se almacenan en los archivos de biblioteca.
En el sistema Linux, todas estas implementaciones de funciones se implementarán en libc.so.6
el archivo de biblioteca nombrado. Si no hay una instrucción especial, gcc buscará en la ruta de búsqueda predeterminada del sistema “/usr/lib”
, es decir, vinculará a la libc.so.6
función de biblioteca. Esto habilita la función "printf" o lo que sea, y eso es lo que hace la vinculación.
Por ejemplo, echemos un vistazo al archivo ejecutable a.fuera del archivo de prueba hello.c escrito arriba, y veamos el archivo de biblioteca al que se vincula. Aquí necesitamos usar ldd
instrucciones para verlo.
De hecho, cuando instalamos compiladores como vs2019 y vs2022, la tarea más importante es ayudarnos a descargar e instalar los archivos de encabezado de idioma y los archivos de biblioteca.
Entonces podemos concluir que la biblioteca de funciones en sí misma es un archivo, que se usa para definir y almacenar funciones.
1. Clasificación de bibliotecas de funciones
Existen dos tipos de bibliotecas de funciones, bibliotecas estáticas y bibliotecas dinámicas, sus diferencias son las siguientes:
(1) Biblioteca dinámica
nombre:libXXXXX.so
Entre ellos, XXXXX puede ser cualquier nombre, como el archivo de biblioteca utilizado anteriormente libc.so.6
, es una biblioteca dinámica. Elimine el prefijo lib y el sufijo .so c
para mostrar que es una biblioteca escrita en lenguaje c, y el .6 restante representa el número de versión.
El papel de la biblioteca dinámica: el archivo de la biblioteca de enlaces dinámicos, en la etapa de enlace, copie la dirección del código que necesitamos en la biblioteca dinámica a la ubicación relevante en nuestro propio programa ejecutable, y llame a la función en la biblioteca dinámica a través del Dirección al ejecutar el programa para garantizar que el código de funcionamiento normal.
Cuando el código que escribimos está vinculado, si no se especifica, el vínculo predeterminado es la biblioteca dinámica.
(2) biblioteca estática
nombre:libXXXXX.a
Como arriba, lib es el prefijo, .a es el sufijo y cualquier nombre puede estar en el medio
El papel de la biblioteca estática: el archivo de biblioteca de enlaces estáticos, al compilar y vincular, copie el código que necesitamos en la biblioteca estática al archivo ejecutable, por lo que el archivo generado es relativamente grande, pero el archivo de biblioteca ya no es necesario en tiempo de ejecución .
Por ejemplo: cuando escribimos un programa, la printf
función puede aparecer más de una vez, luego cada printf
función se reemplazará con el código correspondiente en la biblioteca estática, lo que hará que el archivo sea más grande y las printf
funciones reemplazadas muchas veces desperdician espacio.
Los enlaces estáticos deben ser enlazados por nosotros mismos. El método de enlace es el siguiente:
-
Podemos usar el
file
comando para verificar si el archivo ejecutable está vinculado a una biblioteca dinámica o estática, o usar elldd
comando para verificar el nombre de la biblioteca de enlaces y juzgar según el nombre.
-
gcc hello.c -o hello-static -static
Haga que elhello-static
ejecutable resultante esté vinculado estáticamente a través de una directiva- Es normal que los archivos después del enlace estático y el enlace dinámico difieran aproximadamente 10 veces
-
Estoy usando un servidor en la nube. Por defecto, solo hay bibliotecas dinámicas. Necesitamos instalar manualmente bibliotecas estáticas para usarlas. El método es el siguiente:
sudo yum install -y glibc-static //在普通用户下安装c语言静态库 yum install -y glibc-static //在root用户下安装c语言静态库 sudo yum install -y glibc-static libstdc++-static //在普通用户下安装c++静态库 yum install -y glibc-static libstdc++-static //在root用户下安装c++静态库
2. Diferencia
La biblioteca dinámica llama a la función correspondiente en la biblioteca dinámica a través de la dirección correspondiente al código de la biblioteca dinámica en el programa para completar la ejecución del código.Si la biblioteca dinámica desaparece repentinamente, el programa ejecutable no podrá ejecutarse.
La biblioteca estática encuentra la función correspondiente en la biblioteca a través de la dirección generada por el nombre de la función, la copia en el archivo ejecutable y la llama en el archivo, lo que hace que el archivo ejecutable ejecute código incluso sin una biblioteca estática, pero con la copia , Los ejecutables también aumentan de tamaño.
3. Expansión
Las instrucciones que usamos en Linux están todas escritas en lenguaje C. Podemos revisar las bibliotecas de enlaces de diferentes instrucciones para ver si están escritas en lenguaje C, de la siguiente manera:
Vea el archivo de biblioteca del comando ls:
Ver el archivo de biblioteca del comando which:
Así que las instrucciones son programas.
- Este es el único conocimiento sobre la biblioteca de funciones en este blog, y se explicará más contenido en E/S básica.
4. Memoria
1. Opciones
En los cuatro pasos del entorno de traducción, usamos -o
opciones, y solo usamos enlaces.Podemos recordar los -o
tres pasos restantes a través del botón en la esquina superior izquierda del teclado .Esc
Preprocesamiento—— -E
, compilación—— -S
, compilación——c
Si lo olvidamos, solo tenemos que mirar el Esc
botón en la esquina superior izquierda del teclado, pero tenga en cuenta que E
y S
están en mayúscula.
2. Sufijo
El archivo generado por el enlace no tiene sufijo y no necesita ser memorizado, y los otros tres corresponden al sufijo del archivo de imagen en orden.iso
Opciones de Five.gcc
Entre las opciones de gcc, las opciones más utilizadas son las opciones de los cuatro pasos anteriores del entorno de traducción, que se resumen y se ponen aquí junto con otras opciones para su comodidad.
- -E solo activa el preprocesamiento, esto no produce un archivo, necesita ser redirigido a un archivo de salida.
- -S Compilar en lenguaje ensamblador No ensamblar y vincular.
- -c Compilar en código objeto.
- -o archivo Salida a archivo.
- -static Esta opción vincula estáticamente los archivos generados.
- -g Genera información de depuración. El depurador GNU puede aprovechar este mensaje.
- -shared Esta opción intentará usar la biblioteca dinámica, por lo que el archivo generado es relativamente pequeño, pero el sistema necesita la biblioteca dinámica.
- -O 0
- -O 1
- -El 2
- -O 3 Los 4 niveles de opciones de optimización del compilador, -O0 significa que no hay optimización, -O1 es el valor predeterminado y -O3 tiene el nivel de optimización más alto.
- -w No genera ningún mensaje de advertencia.
- -Wall Generar todos los mensajes de advertencia.