首页 > 编程语言 >C源码到可执行文件的preprocess/compile/assemble/link四阶段

C源码到可执行文件的preprocess/compile/assemble/link四阶段

时间:2023-07-12 13:55:48浏览次数:48  
标签:gcc main compile source 源码 usr file assemble include

 

C源码到可执行文件的preprocess/compile/assemble/link四阶段_zh_yt的博客-CSDN博客

 

 

 

C源码到可执行文件的preprocess/compile/assemble/link四阶段

参考资料

http://www.thegeekstuff.com/2011/10/c-program-to-an-executable/
http://courses.cms.caltech.edu/cs11/material/c/mike/misc/compiling_c.html
预处理器: https://en.wikipedia.org/wiki/Preprocessor
编译器: https://en.wikipedia.org/wiki/Compiler
链接器: https://en.wikipedia.org/wiki/Linker_(computing)
ELF格式: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format

gcc help

$ gcc --help

-save-temps              Do not delete intermediate files
-E                       Preprocess only; do not compile, assemble or link
-S                       Compile only; do not assemble or link
-c                       Compile and assemble, but do not link
-o <file>                Place the output into <file>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

对c文件,想要保留中间文件,执行下面命令:

$ gcc -Wall -save-temps hello.c

// 会生成文件
hello.i
hello.s
hello.o
a.out
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

下面一一说明。

(1)Pre-processing

-E    Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.
      Input files that don't require preprocessing are ignored.
  • 1
  • 2

预处理的任务是:

  • Macro substitution 宏(#define)替换
  • Comments are stripped off 删注释
  • Expansion of the included files 展开包含文件(#include)的声明

预处理可以理解成:把你所写的源代码转换成扩展的完整源代码。

What the preprocessor does is convert the source code file you write into another source code file (you can think of it as a “modified” or “expanded” source code file).

使用 -save-temps 选项时,预处理的输出被存放进了 .i 文件。

包含文件的搜索路径-Idir和-iquotedir:

参考:man gcc

  • -Idir

Add the directory dir to the head of the list of directories to be searched for header files. This can be used to override a system header file, substituting your own version, since these directories are searched before the system header file directories.

If you use more than one -I option, the directories are scanned in left-to-right order; the standard system directories come after.

If you really need to change the search order for system directories, see the -nostdinc and/or -isystem options.

  • -iquotedir

Add the directory dir to the head of the list of directories to be searched for header files only for the case of #include "file"; they are not searched for #include <file>, otherwise just like -I.

关于双引号#include "file"的搜索路径:

参考:https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html

GCC looks for headers requested with #include "file" first in the directory containing the current file, then in the directories as specified by -iquote options, then in the same places it would have looked for a header requested with angle brackets.

包含文件搜索路径小结:

  • 尖括号#include <file>-I和系统default的目录这两个地方搜索。
  • 双引号#include "file"从:1当前目录,2-iquote指定的目录,3#include <file>使用的搜索目录。

包含文件搜索路径的实验一

/*
 * 源码文件结构:
 * |-main.c
 * |-zzz
 *     |-myfile.h
 */

// main.c源码
#include <stdio.h>
#include "myfile.h"

int main(int argc, char **argv)
{
    printf("hello\n");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

编译1:

$ gcc -Wall main.c

main.c:2:20: fatal error: myfile.h: 没有那个文件或目录
 #include "myfile.h"
                    ^
compilation terminated.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

编译2:

$ gcc -v -I ./zzz main.c

#include "..." search starts here:
#include <...> search starts here:
 ./zzz
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

编译3:

$ gcc -v -iquote ./zzz main.c

#include "..." search starts here:
 ./zzz
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

从实验一的打印信息可以看出-Idir和-iquotedir的区别。

包含文件搜索路径的实验二

/*
 * 源码文件结构:
 * |-main.c
 * |-myfile2.h
 * |-zzz
 *     |-myfile.h
 */

// main.c源码
#include <stdio.h>
#include "myfile2.h"
#include "myfile.h"

int main(int argc, char **argv)
{
    printf("hello\n");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

编译4:

$ gcc -Wall main.c

main.c:3:20: fatal error: myfile.h: 没有那个文件或目录
 #include "myfile.h"
                    ^
compilation terminated.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

编译5:

$ ls -F
main.c  myfile2.h  zzz/

----------

$ gcc -v -iquote ./zzz  main.c

#include "..." search starts here:
 ./zzz
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

----------

$ ls -F
a.out*  main.c  myfile2.h  zzz/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

编译6:
为了测试需要,在当前目录下新建一个空目录:

$ ls -F
main.c  myfile2.h  zzz/

$ mkdir yyy

$ ls -F
main.c  myfile2.h  yyy/  zzz/
----------

(这里命令行里故意把-I放在-iquote前面:)
$ gcc -v -I ./yyy -iquote ./zzz  main.c

#include "..." search starts here:
 ./zzz
#include <...> search starts here:
 ./yyy
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

----------
$ ls -F
a.out*  main.c  myfile2.h  yyy/  zzz/

$ ./a.out 
hello
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

从实验二的打印信息可以看出,虽然没有显式地打印出使用了当前目录,但GCC实际上确实使用了当前目录来搜索双引号的头文件。并且可以看出先-iquote目录、后-I目录的搜索顺序。

(2)Compilation

-S    Stop after the stage of compilation proper; do not assemble. The output is in the form of an assembler code file for each non-assembler input file specified.
      By default, the assembler file name for a source file is made by replacing the suffix .c, .i, etc., with .s.
      Input files that don't require compilation are ignored.
  • 1
  • 2
  • 3

编译的任务是:

  • 生成汇编指令代码文件

使用 -save-temps 选项时,编译的输出被存放进了 .s 文件。

(3)Assembly

-c    Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file.
      By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o.
      Unrecognized input files, not requiring compilation or assembly, are ignored.
  • 1
  • 2
  • 3
  • 4

汇编的任务是:

  • 把汇编指令翻译成二进制的目标文件(参见ELF格式)

本阶段只有本文件存在的代码才被翻译成二进制机器语言。

At this stage only the existing code is converted into machine language, the function calls like printf() are not resolved.

使用 -save-temps 选项时,汇编的输出被存放进了 .o 即目标文件。

注意:在不细分的情况下,可以把编译(compile)和汇编(assembly)两个过程合称为编译。

(4)Linking

-o file
    Place output in file file. This applies to whatever sort of output is being produced, whether it be an executable file, an object file, an assembler file or preprocessed C code.
    If -o is not specified, the default is to put an executable file in a.out, the object file for source.suffix in source.o, its assembler file in source.s, a precompiled header file in source.suffix.gch, and all preprocessed C source on standard output.
  • 1
  • 2
  • 3

链接的任务是:

  • 把生成的目标文件(.obj)和库(lib)文件等链接,生成可执行(exe)文件、库(lib)文件、其他文件(如dll)等。

在前面几个阶段,gcc可能并不知道某些函数等的定义(例如printf()),只是在函数调用处放了个占位符(place-holder )。
在本阶段,printf()的函数定义被解析出来,其真实地址被放入。

As discussed earlier, till this stage gcc doesn’t know about the definition of functions like printf(). Until the compiler knows exactly where all of these functions are implemented, it simply uses a place-holder for the function call. It is at this stage, the definition of printf() is resolved and the actual address of the function printf() is plugged in.

总结

  • preprocessor 预处理器cpp

  • compiler 编译器ccas

    It does this by turning the C source code into an object code file, which is a file ending in “.o” which contains the binary version of the source code. Object code is not directly executable, though.
    In order to make an executable, you also have to add code for all of the library functions that were #included into the file (this is not the same as including the declarations, which is what #include does). This is the job of the linker.

  • linker 链接器ld

    The job of the linker is to link together a bunch of object files (.o files) into a binary executable. This includes both the object files that the compiler created from your source code files as well as object files that have been pre-compiled for you and collected into library files. These files have names which end in .a or .so, and you normally don’t need to know about them, as the linker knows where most of them are located and will link them in automatically as needed.

  • 整个过程:

sourceFile --[preprocessor]--> newSourceFile 
--[compiler]--> objectFile 
--[linker+library]--> executableFile
 

 

 

标签:gcc,main,compile,source,源码,usr,file,assemble,include
From: https://www.cnblogs.com/sinferwu/p/17547301.html

相关文章

  • 跨境电商外贸商城产品展示源码-多商户汉化Woodmart主题
    源码说明:WoodMart是一个WordPress商城主题,专注于用户体验第一WoodMart采用了功能强大的AJAX技术为用户提供了非常快速和无缝的网上购物界面。建立任何形式的网上商店,并开始赚取被动收入流。70个各行业商城模板。Html5+css3响应式,主题文件80%以上汉化,插件80%以上汉化模板用途:......
  • 【Netty】「源码解析」(三)设置连接超时:深入分析 ChannelFuture.sync() 的执行过程
    前言本篇博文是《从0到1学习Netty》中源码系列的第三篇博文,主要内容是深入分析连接超时的实现原理,包括了connect方法的源码解析和ChannelFuture.sync()执行过程的解析。,往期系列文章请访问博主的Netty专栏,博文中的所有代码全部收集在博主的GitHub仓库中;介绍在实际应用中,当......
  • 使用LabVIEW实现 DeepLabv3+ 语义分割含源码
    (文章目录)前言图像分割可以分为两类:语义分割(SemanticSegmentation)和实例分割(InstanceSegmentation),前面已经给大家介绍过两者的区别,并就如何在labview上实现相关模型的部署也给大家做了讲解,今天和大家分享如何使用labview实现deeplabv3+的语义分割,并就PascalVOC2012(DeepL......
  • 老杜 JavaWeb 讲解(九) ——模板方法设计模式、HttpServlet源码分析
    (十一)模板方法设计模式、HttpServlet源码分析对应视频:20-HttpServlet源码分析及web欢迎页11.1模板方法设计模式不用使用在上面右侧表格中,Person就是模板方法设计模式当中的模板类,通常是抽象类。day()方法就是模板方法设计模式当中的模板方法。模......
  • 【.NET源码解读】深入剖析中间件的设计与实现
    合集-.NET源码解读系列(4) 1..NET通过源码深究依赖注入原理05-172.【.NET源码解读】Configuration组件及自动更新05-303..NET源码解读kestrel服务器及创建HttpContext对象流程06-164.【.NET源码解读】深入剖析中间件的设计与实现06-29收起 .NET本身就是一个基于......
  • day-3 路由底层源码
    1.定义路由本质比如在url.py定义以下路由,浏览器中输入http://192.168.0.1:8000/user/2003-04-21可以访问意味着此urlhttp://192.168.0.1:8000/user/2003-04-21和url.py里的路由们做了路由匹配如果匹配成功找到相应的试图函数  源码解析ctrl+鼠标左键点进re_path,会发......
  • 使用LabVIEW实现 DeepLabv3+ 语义分割含源码
    前言图像分割可以分为两类:语义分割(SemanticSegmentation)和实例分割(InstanceSegmentation),前面已经给大家介绍过两者的区别,并就如何在labview上实现相关模型的部署也给大家做了讲解,今天和大家分享如何使用labview实现deeplabv3+的语义分割,并就PascalVOC2012(DeepLabv3Plus-Mo......
  • 视频直播源码,调整颜色,附颜色大全
    视频直播源码,调整颜色,附颜色大全使用示范:importmatplotlib.pyplotaspltplt.imshow(data.images[0],   #负责对图像进行处理 imge类型:<class'numpy.ndarray'>      cmap=plt.cm.gray_r,    #cmap参数:为调整显示颜色 gray为黑白色,加_r取反为......
  • 禁忌搜索算法解决配电网无功优化问题对应的MATLAB源码,有对应的参考资料。
    禁忌搜索算法解决配电网无功优化问题对应的MATLAB源码,有对应的参考资料。电力系统配电网的无功优化规划是保证配电网安全、经济运行的一项有效手段,是降低网损、提高电压质量的重要措施。因此,电力系统配电网无功优化规划问题的研究,既具有理论意义,又具有工程实际应用价值。配电系统......
  • The Deep Learning Compiler: A Comprehensive Survey
    TheDeepLearningCompiler:AComprehensiveSurveyAI编译器综述摘要介绍背景深度学习框架深度学习硬件DL编译器设计体系DL编译器的关键组成High-levelIRgraphIR表示GraphIR的实现,包括数据和算子的管理小结Low-levelIRLow-levelIR的实现Low-level......