静态链接——编译和链接

这篇具有很好参考价值的文章主要介绍了静态链接——编译和链接。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、编译和链接的过程

1、GCC生成可执行文件的总体过程

在日常的开发过程中,IDE总是会帮我们将编译和链接合并,一键式的执行,即使在liunx中,使用命令行来编译一个源文件也只是简单的一句"gcc hello.c"。我们并没有过多的关注编译和链接的运行机制和机理,我想从本质出发,深入了解这些机制。对于下面一段hello.c代码
#include <stdio.h>
int main()
{ 
  printf("Hello World\n");
  return 0;
}
在liunx中,当我们用GCC来编译时只需要`gcc hello.c`即可生成`a.out`文件(并不是所有可执行文件都是`.out`),使用`./a.out`即可运行输出。实际上,上述的过程可以分解为四个步骤,分别是预处理(Prepressing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。

静态链接——编译和链接

                                                                            GCC编译过程分解

1.1、预编译(Prepressing)

预编译是指将源代码文件`(hello.c)`和相关头文件`(stdio.h)`等被**预编译器cpp**预编译成一个`.i`文件。需要注意的是对于C++程序来说,它的源代码文件的扩展名可能是`.cpp或.cxx`,头文件的扩展名可能是`.hpp`,而预编译后的文件扩展名是`.ii`。第一步预编译的过程相当于如下命令(E表示只进行预编译):` gcc -E hello.c -o hello.i 或者 cpp hello.c > hello.i`

预编译过程主要处理那些源代码文件中的以“#”开始的预编译指令。比如“#include”、“#define”等,主要处理规则如下:
  • 将所有的“define”删除,并且展开所有的宏定义。

  • 处理所有条件预编译指令,比如“#if”、“#ifdef'”、“#elif”、“#else”、“#endif'”。

  • 处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。

  • 删除所有的注释。

  • 添加行号和文件名标识,比如#2“hello.c”2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。

  • 保留所有的#pragma编译器指令,因为编译器要使用它们。

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 375 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 392 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 393 "/usr/include/sys/cdefs.h" 2 3 4
# 376 "/usr/include/features.h" 2 3 4
# 399 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 10 "/usr/include/gnu/stubs.h" 3 4
# 1 "/usr/include/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/gnu/stubs.h" 2 3 4
# 400 "/usr/include/features.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4
部分展示

经过预编译后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到.i文件中。所以当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定问题。

1.2、编译(Compilation)

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件,这个过程往往是我们所说的整个程序构建的核心部分,也是最复杂的部分之一。上面的编译过程相当于如下命令:

gcc -S hello.i -o hello.s

现在版本的GCC把预编译和编译两个步骤合并成一个步骤,使用一个叫做cc1的程序来完成这两个步骤。这个程序位于`usr/lib/gcc/i486-linux-gnu/4.1/`,我们也可以直接调用 ccl来完成它:

usr/lib/gcc/i486-linux-gnu/4.1/cc1 hello.c或者gcc -S hello.c -o hello.s都可以得到汇编输出文件helIo.s。对于C语言的代码来说,这个预编译和编译的程序是ccI,对于C++来说,有对应的程序叫做cclplus:Objective-C是cclobj::fortran是f77l;Java是 jc1。所以实际上gcc这个命令只是这些后台程序的包装,它会根据不同的参数要求去调用预编译编译程序cc1、汇编器as、链接器ld。

	.file	"hello.c"
	.section	.rodata
.LC0:
	.string	"hello world"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$.LC0, %edi
	movl	$0, %eax
	call	printf
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
	.section	.note.GNU-stack,"",@progbits
展示hello.s中的内容

1.3 汇编

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了,“汇编”这个名字也来源于此。上面的汇编过程我]可以调用汇编器as来完成:

as hello.s -o hello.o或者gcc -c hello.s -o hello.o或者使用gcc命令从C源代码文件开始,经过预编译、编译和汇编直接输出目标文件(Object File):gcc -c hello.c -o hello.o

1.4 链接

链接通常是一个让人比较费解的过程,为什么汇编器不直接输出可执行文件而是输出一个目标文件呢?链接过程到底包含了什么内容?为什么要链接?这恐怕是很多读者心中的疑惑。正是因为这些疑惑总是挥之不去,所以我们特意用这一章的篇幅来分析链接,具体地说分析静态链接的章节。下面让我们来看看怎么样调用ld才可以产生一个能够正常运行的 HelloWorld程序:
$ld -static /usr/lib/crt1.o /usr/lib/crti.o /uar/lib/gcc/1486-linux-gnu/4.1.3/crtbeginT.o -L/usr/lib/gcc/1486-linux-gnu/4.1.3 -L/usr/lib -L/lib hello.o --start-group-lgcc -lgcc_eh -1c --end-group /uar/lib/gcc/1486-linux-gnu/4.1.3/crtend.o /usr/lib/crtn.o

如果把所有的路径都省略掉,那么上面的命令就是:

ld -static crt1.o crti.o crtbeginT.o hello.o -start-group -lgcc -lgcc_eh -lc-end-group crtend.o crtn.o
	可以看到,我们需要将一大堆文件链接起来才可以得到“a.out”,即最终的可执行文件。看了这行复杂的命令,可能很多读者的疑惑更多了,ctl.o、crti.o、crtbegin T.o、crtend.o、 crtn.o这些文件是什么?它们做什么用的?-lgcc-lgcc_ehlc这些都是什么参数?为什么要使用它们?为什么要将它们和hello.o链接起来才可以得到可执行文件?等等。后面我们会陆续讲解

参考:《程序员的自我修养》俞甲子文章来源地址https://www.toymoban.com/news/detail-529632.html

到了这里,关于静态链接——编译和链接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GCC编译过程:预处理->编译->汇编->链接

    目录 引言  概括介绍 一、预处理 二、编译 三、汇编 四、链接 总结 当使用集成开发环境(IDE)进行C语言编程时,点击\\\" 编译 \\\"按钮后,整个C程序从源代码到可执行文件的生成过程会自动完成。IDE会在后台为我们执行C语言的编译过程,将源代码转换为最终的可执行文件。虽

    2024年02月13日
    浏览(47)
  • 【iOS内存管理-编译链接的过程】

    就我而言,iOS开发的过程中接触到的编译链接方面的知识很少,这部分知识还是很重要的。 对于iOS的编译链接过程来说并不难,和微机原理的汇编过程还是挺像的。今天对于编译链接的过程学习和了解一下。 参考:iOS程序员的自我修养-编译、链接过程 参考:iOS编译过程 计

    2024年02月16日
    浏览(43)
  • Windows下C++静态链接库的生成以及使用

    这篇文章简单讨论一下Windows下如何使用VS生成和使用C++静态链接库,示例使用VS2022环境。 先创建C++项目-静态库 然后将默认生成的.h和.cpp文件清理干净,当然你也可以选择保留。 然后创建需要的.h和.cpp文件。 看下代码 很简单的代码,就是提供一个打印字符串的接口。编译一

    2024年02月05日
    浏览(37)
  • 【Linux初阶】基础IO - 动静态库 | 初识、生成、链接、加载

    🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux初阶】 ✒️✒️本篇内容:动静态库初识,库的含义,静态库的生成与链接,gcc/g++默认链接方式,动态库的生成与动态链接,查看动态链接的方法,动静态库的加载原理 🚢🚢作者简介:计算机海洋的新进船长一

    2024年02月14日
    浏览(35)
  • 【Linux】Linux编译器 gcc/g++的使用&&初识动静态链接库

    ​ ​📝个人主页:@Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:Linux 🎯 长路漫漫浩浩,万事皆有期待 上一篇博客:【Linux】Linux环境基础工具的基本使用及配置(yum、vim) 在上一篇 Linux 博客中,我们讲解了 vim 编辑器的使用,可以在 Linux 上写

    2024年02月11日
    浏览(55)
  • C语言中程序的编译(预处理操作)+链接详解(详细介绍程序预编译过程)

    今天我们来学习C语言中程序的编译和链接是如何进行的。 在ANSI C的任何一种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。 第2种是执行环境,它用于实际执行代码。 本文主要是介绍预编译阶段的相关知识。 1.组成一个程

    2023年04月09日
    浏览(39)
  • Linux gcc/g++编译链接头文件和库(动态库.so 和 静态库.a)

    最近在学习log4cpp库时,使用g++去编译,却发现自己不会链接...,这哪能行,于是网上钻研,终于解决,现在记录下来分享给遇到同样问题的人。 gcc和g++类似,这里就以g++为例! 刚好用到的log4cpp日志库有头文件和动态库.so和静态库.a,这里就以log4cpp库为例。 在安装好log4cpp库

    2024年02月08日
    浏览(55)
  • Linux编译链接选项静态库--whole-archive,--no-whole-archive

    在使用cmake构建工程时,目标可执行程序可以正常构建,但是运行不符合预期。可执行程序依赖libtool.a静态库,静态库有个全局map,map中存放注册的回调函数。在可执行程序运行时发现map为空,检查代码逻辑,libtool.a中存在注册行为。 1、通过nm定位出相关符号表在libtool.a中存

    2024年02月07日
    浏览(33)
  • VS2019编译生成动态链接库dll的两种方式

     dll项目的默认结构如下:  四个文件的内容因为是默认生成的,不是特别重要, 接下来就是重要的修改部分: 方法一: 修改“pch.h”和“dllmain.cpp”文件,可以参考以下博主链接,但博主的引用部分有些繁琐,文末会介绍我的引用方法,和正常引用外部库步骤是一样的。这

    2023年04月09日
    浏览(49)
  • 【使用过程】weevely生成、上传、连接、执行…你一定行

    目录 weevely前言: 简介: 使用方法: 第一步:查看是否安装weevely,并查看版本信息 第二步:生成shell(php)文件 第二步:上传文件到目标服务器  第三步:在终端使用weevely,连接到shell(php文件) 第四步:执行相关系统命令,获取相关信息 第五步:调用weevely模块 小白初

    2024年02月08日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包