Linux 9:GCC编译全流程详解

🔥个人主页: Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

<<Git>><<MySQL>>

🌟心向往之行必能至

目录

二.编译器gcc/g++

[2.1 gcc编译选项](#2.1 gcc编译选项)

2.2编译过程

[2.2.1 预处理(进⾏宏替换/去注释/条件编译/头⽂件展开等)](#2.2.1 预处理(进⾏宏替换/去注释/条件编译/头⽂件展开等))

[2.2.2. 编译(⽣成汇编)](#2.2.2. 编译(⽣成汇编))

[2.2.3 汇编(⽣成机器可识别代码)](#2.2.3 汇编(⽣成机器可识别代码))

[2.2.4 连接(⽣成可执⾏⽂件或库⽂件)](#2.2.4 连接(⽣成可执⾏⽂件或库⽂件))

2.2.5如何理解条件汇编

2.2.6为什么要把语言弄成汇编

2.3静态链接(浪费空间,更新困难)

2.4动态链接(节省空间,更新简单)

[2.4.1 验证动态链接](#2.4.1 验证动态链接)

[2.5 静态库](#2.5 静态库)

[2.5 动态库](#2.5 动态库)

三.解决sudo权限问题

[2.6 库的使用(防止源码泄漏)](#2.6 库的使用(防止源码泄漏))


二.编译器gcc/g++

2.1 gcc编译选项

格式 gcc [ 选项 ] 要编译的⽂件 [ 选项 ] [ ⽬标⽂件 ]

2.2编译过程

先使用vim编辑一个输出hello world的文件,再进行gcc

bash 复制代码
[lcb@hcss-ecs-1cde test]$ vim code.c
[lcb@hcss-ecs-1cde test]$ gcc code.c
[lcb@hcss-ecs-1cde test]$ ll
total 16
-rwxrwxr-x 1 lcb lcb 8360 Dec 12 19:22 a.out
-rw-rw-r-- 1 lcb lcb   71 Dec 12 19:22 code.c
[lcb@hcss-ecs-1cde test]$ ./a.out
hello wordl

那么上面gcc是如何编译的呢?

2.2.1 预处理(进⾏宏替换/去注释/条件编译/头⽂件展开等)

• 预处理指令是以#号开头的代码⾏。

bash 复制代码
[lcb@hcss-ecs-1cde test]$ gcc -E code.c -o code.i

选项"-E",该选项的作⽤是让 gcc 在预处理结束后停⽌编译过程。
• 选项"-o"是指⽬标⽂件,".i"⽂件为已经过预处理的C原始程序。

2.2.2. 编译(⽣成汇编)

• 在这个阶段中,gcc ⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作,
在检查⽆误后,gcc 把代码翻译成汇编语⾔。
• ⽤⼾可以使⽤"-S"选项来进⾏查看,该选项只进⾏编译⽽不进⾏汇编,⽣成汇编代码。
实例:

bash 复制代码
[lcb@hcss-ecs-1cde test]$ gcc -S code.i -o code.s
[lcb@hcss-ecs-1cde test]$ ll
total 44
-rwxrwxr-x 1 lcb lcb  8360 Dec 12 19:22 a.out
-rw-rw-r-- 1 lcb lcb     6 Dec 12 19:26 code
-rw-rw-r-- 1 lcb lcb    71 Dec 12 19:22 code.c
-rw-rw-r-- 1 lcb lcb 16869 Dec 12 19:27 code.i
-rw-rw-r-- 1 lcb lcb   447 Dec 12 19:32 code.s

2.2.3 汇编(⽣成机器可识别代码)

汇编阶段是把编译阶段⽣成的".s"⽂件转成⽬标⽂件
读者在此可使⽤选项"-c"就可看到汇编代码已转化为".o"的⼆进制⽬标代码了
实例:

bash 复制代码
[lcb@hcss-ecs-1cde test]$ gcc -c code.s -o code.o
[lcb@hcss-ecs-1cde test]$ ll
total 48
-rwxrwxr-x 1 lcb lcb  8360 Dec 12 19:22 a.out
-rw-rw-r-- 1 lcb lcb     6 Dec 12 19:26 code
-rw-rw-r-- 1 lcb lcb    71 Dec 12 19:22 code.c
-rw-rw-r-- 1 lcb lcb 16869 Dec 12 19:27 code.i
-rw-rw-r-- 1 lcb lcb  1496 Dec 12 19:34 code.o
-rw-rw-r-- 1 lcb lcb   447 Dec 12 19:32 code.s

2.2.4 连接(⽣成可执⾏⽂件或库⽂件)

在成功编译之后,就进⼊了链接阶段。
实例:

bash 复制代码
[lcb@hcss-ecs-1cde test]$ gcc code.o -o code

对于上面类似第一个选项有 ESc记法(键盘左上角) 第二个选项有iso(镜像)


2.2.5如何理解条件汇编

1.条件汇编也有命令行执行

2.条件汇编的用途

在我们的实际开发中,不可能将所有代码放在⼀个源⽂件中,所以会出现多个源⽂件,⽽且多个源⽂ 件之间不是独⽴的,⽽会存在多种依赖关系,此时就需要通过链接

2.2.6为什么要把语言弄成汇编

早期计算机不发达的时候,先是按钮执行指令,再到后来的纸带(通过不通过,二态,类似二进制),但要是有一个孔打错,那么这条纸带就报废了,效率低,浪费,后面就出现了汇编语言,汇编语言会转换为二进制,交给计算机解析

注:汇编语言是文本,更有利于人们理解与使用

2.3静态链接(浪费空间,更新困难)

⼀个源⽂件可能要调⽤另⼀个源⽂件中定义的函数,
但是每个源⽂件都是独⽴编译的,即每个*.c⽂件会形成⼀个*.o⽂件

上面就是静态链接,即每次在链接的时候,都需要把printf拷贝到被调用的地方(可见,静态库只需在链接的时候有用即可)

但缺点极大

浪费空间:因为每个可执⾏程序中对所有需要的⽬标⽂件都要有⼀份副本,所以如果多个程序对 同⼀个⽬标⽂件都有依赖,如多个程序中都调⽤了printf()函数,则这多个程序中都含有
printf.o,所以同⼀个⽬标⽂件都在内存存在多个副本;

更新⽐较困难:因为每当库函数的代码修改了,这个时候就需要重新进⾏编译链接形成可执⾏程 序。但是静态链接的优点就是,在可执⾏程序中已经具备了所有执⾏程序所需要的任何东西,在 执⾏的时候运⾏速度快。

2.4动态链接(节省空间,更新简单)

此时的动态链接的出现解决了静态链接中提到问题。动态链接的基本思想是把程序按照模块拆分成各个相对 独⽴部分,在程序运⾏时才将它们链接在⼀起形成⼀个完整的程序,⽽不是像静态链接⼀样把所有程序模块都链接成⼀个单独的可执⾏文件

即动态链接是把调用动态库的地址给到被调用的对象,空间小,且更新简单(只需在库更新一次,所以被调用的都会更新)

2.4.1 验证动态链接

bash 复制代码
$ ldd hello
linux-vdso.so.1 => (0x00007fffeb1ab000)
libc.so.6 => /lib64/libc.so.6 (0x00007ff776af5000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff776ec3000

此处的第三行 .sp就是一个动态链接,库函数名为c

2.5 静态库

静态库是指编译链接时,把库⽂件的代码全部加⼊到可执⾏⽂件中,因此⽣成的⽂件⽐较⼤,但在运
⾏时也就不再需要库⽂件了。其后缀名⼀般为".a"

一般云服务器,没有预装c/c++的静态库,需手动安装

bash 复制代码
# Centos
yum install glibc-static libstdc++-static -y

2.5 动态库

当调用的指令是一个动态库时,在内存会记录该动态库的地址,后面再有该调用相同动态库的指令,无需在内存中再加载,可以直接调用前面缓存的,节省空间

同样的,如果我们把动态库删除,那么相关指令都无法执行,哪怕已经链接好

Linux下,动态库XXX.so, 静态库XXX.a
Windows下,动态库XXX.dll, 静态库XXX.lib

三.解决sudo权限问题

我们会遇到,对普通用户使用sudo,哪怕输对了密码,仍是无权限,其实就是未加入用户名

1.先把用户切换到超级用户,再输入这行代码

bash 复制代码
 vim /etc/sudoers

2.找到100行左右

,

3.yy root这行代码,再p复制,最后将root改为你要加入白名单的用户名

2.6 库的使用(防止源码泄漏)

实例

bash 复制代码
hello func1hello func2[lcb@hcss-ecs-1cde 1]$ vim code1.c
[lcb@hcss-ecs-1cde 1]$ gcc code1.c code2.c main.c -o code
[lcb@hcss-ecs-1cde 1]$ ./code
hello func1
hello func2
[lcb@hcss-ecs-1cde 1]$ ll
total 40
-rwxrwxr-x 1 lcb lcb 8480 Dec 12 22:07 code
-rw-rw-r-- 1 lcb lcb   63 Dec 12 22:06 code1.c
-rw-rw-r-- 1 lcb lcb   24 Dec 12 22:01 code1.h
-rw-rw-r-- 1 lcb lcb   65 Dec 12 22:06 code2.c
-rw-rw-r-- 1 lcb lcb   24 Dec 12 21:58 code2.h
drwxrwxr-x 2 lcb lcb 4096 Dec 12 21:51 lib
-rw-rw-r-- 1 lcb lcb   69 Dec 12 22:06 main.c
drwxrwxr-x 2 lcb lcb 4096 Dec 12 19:36 test

上面我们为了让main.c能够成功地调用code1.c与code2.c,把code./h与main.c放在同一目录下进行编译,虽然可行,但会因此暴露源码,不安全

解决办法,提前进行编译,再将编译后的.o与.c与main.c放在同一目录 ,即可确保main.c调用库,且不会泄漏源码

相关推荐
赋创小助手2 小时前
Maia 200 技术拆解:微软云端 AI 推理加速器的设计取舍
服务器·人工智能·科技·深度学习·神经网络·microsoft·自然语言处理
Once_day2 小时前
C++之《Effective C++》读书总结(1)
c语言·c++·effective c++
他人是一面镜子,保持谦虚的态度2 小时前
ubuntu 18.04 压缩 激光雷达点云和图像 topic,并录制bag 数据包
linux·运维·ubuntu
Byte不洛2 小时前
Linux 多线程编程入门:线程栈、TLS、互斥锁与条件变量详解
linux·操作系统·多线程·pthread·线程互斥
DeeplyMind2 小时前
VSCode 附加进程调试完整指南
ide·vscode·编辑器·gdb附加调试
2501_945837432 小时前
腾讯云边缘容器服务,云边协同打通云原生最后一公里
服务器
爱吃生蚝的于勒2 小时前
【Linux】进程信号的保存(二)
linux·运维·服务器·c语言·数据结构·c++·算法
HalvmånEver2 小时前
Linux:线程的概念、与进程区别及内核实现(线程一)
java·linux·运维
pass_port_csdn2 小时前
zotero搬家,迁移换机/重装100% 完美克隆指南:文献PDF、插件配置、文献分类、标签、笔记等所有信息全克隆
笔记·pdf·zotero