C程序生成原理

  • 目标文件:

1. 可执行目标文件: 可以直接在内存中执行;

2. 可重定向目标文件: 可与其他可重定向目标文件在链接阶段合并, 创建一个可执行目标文件;

3. 共享目标文件: 可以在运行时被动态加载进内存并链接;

  • 静态连接器

以一组可重定向目标文件为输入, 生成一个完全链接的可执行目标文件作为输出。 链接器主要完成以下两
个任务:
1. 符号解析: 每个符号对应于一个函数、 一个全局变量或一个静态变量, 符号解析的目的是将每个符号引用与一个
符号定义关联起来。
2. 重定位: 编译器和汇编器生成从地址 0 开始的代码和数据节, 链接器通过把每个符号定义与一个内存位置关联
起来, 从而重定位这些节, 然后修改所有对这些符号的引用, 使得它们指向这个内存位置。

  • 动态链接:

静态库有以下两个问题:
当静态库更新时那么整个程序都要重新进行链接;
对于 printf 这种标准函数库, 如果每个程序都要有代码, 这会极大浪费资源。
共享库是为了解决静态库的这两个问题而设计的, 在 Linux 系统中通常用 .so 后缀来表示, Windows 系统上它
们被称为 DLL。 它具有以下特点:
1. 在给定的文件系统中一个库只有一个 .so 文件, 所有引用该库的可执行目标文件都共享这个文件, 它不会被复
制到引用它的可执行文件中;
2. 在内存中, 一个共享库的 .text 节的一个副本可以被不同的正在运行的进程共享。

前处理

这就是所有这些#defines#includes的含义

C预处理是一个非常简单的过程:剪切粘贴。

当预处理器看到以下MyCode.c时:

#include "MyHeader.h"

void main(){
    FunctionDefinedInHeader();
}

,只需打开文件MyHeader.h,然后将其内容粘贴到MyCode.c中:


// Begin of MyCode.c
// Begin of MyHeader.h
#ifndef MYHEADER_H
#define MYHEADER_H

void FunctionDefinedInHeader(); // Declare the function

# endif
// End of MyHeader.h

void main(){
    FunctionDefinedInHeader(); // Use it
}

// End of MyCode

同样地,#定义 s的cut'n粘贴的#if s的分析和潜在的除去等

在此步骤的最后,我们有一个预处理的C ++文件,没有任何#define,#if,#ifdef,#include,可以进行编译了。

汇编

编译器将C ++代码转换为CPU可以直接理解的表示形式。例如,以下代码:

int i=3;
int j=4*i+2;

将被翻译为:x86操作码。


mov         dword ptr [i],3
mov         eax,dword ptr [i]
lea         ecx,[eax*4+2]
mov         dword ptr [j],ecx

每个.cpp文件是分别编译的,结果二进制代码写在.o / .obj文件中。

请注意,我们还没有可执行文件:还需要执行一个步骤。

连结中

链接器获取所有二进制代码(您的代码,以及来自外部库的代码),并生成最终的可执行文件。一些注意事项:

  • 库具有.lib扩展名。
  • 有些库是静态的这意味着.lib包含所有需要的x86操作码。
  • 一些库是动态的(也称共享)。这意味着.lib不包含任何x86代码。它只是说“我发誓功能FooBarWhatsNot将在运行时可用”。

链接器运行后,您将拥有一个可执行文件(Windows上为.exe,Unix上为.nothing_at_all):

运行

启动可执行文件时,操作系统将打开.exe,然后将x86操作码放入内存。如前所述,某些代码目前尚不可用:动态库中的代码。但是链接器很好,可以说在哪里寻找它:.exe清楚地表明glClearColor函数是在OpenGL32.dll中实现的。

Windows将愉快地打开.dll并找到glClearColor:

有时找不到.dll,可能是因为您搞砸了安装过程,并且程序无法运行。

原文地址:https://www.cnblogs.com/wwhhgg/p/12620257.html