【linux】linux编译器-gcc/g++的使用、如何才能让普通用户进行sudo提权
小编个人主页详情<—请点击
小编个人gitee代码仓库<—请点击
linux系列专栏<—请点击
倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己!
目录
- 前言
- 一、sudo提权
- 二、gcc/g++的简单使用
- 三、gcc/g++编译器的执行步骤
- 1. 预处理
- 2. 编译
- 3. 汇编
- 4. 链接
- 四、库
- 1. 库的介绍
- 2. 我们的.o文件和库是如何进行链接的
- 五、debug和release
- 总结
前言
【linux】linux编辑器-vim的使用及简单配置—书接上文详情请点击<—
本文由小编为大家讲解—linux编译器-gcc/g++的使用
一、sudo提权
在正式讲解本文内容之前,小编先为大家介绍一个如何将一个普通用户进行sudo提权呢?
普通用户想要使用sudo提权,是无法进行使用的,因为你未被添加到系统白名单中,系统默认不信任你,那么我们应该如何做才能被添加到系统白名单中呢?
- 使用root用户,vim的使用请点击<—使用vim打开/etc/sudoers
- 打开后下翻至大约100行,复制一下root那一行,在root的下一行粘贴一下,并且将root修改为你所要添加至系统白名单的用户即可
- 添加完成后,由于该文件的权限是只读的r,所以我们需要在底行模式中!wq强制保存退出即可
- 返回我们的普通用户,这时候我们就可以对任意指令进行sudo提权,以root用户的权限执行指令了
二、gcc/g++的简单使用
gcc是用于编译c语言的,由于c++兼容c语言,所以g++可以用于编译c++也可以用于编译c语言,不过小编推荐读者友友们专门使用gcc编译c语言,g++编译c++,这两者的对应关系不要弄反哦
- gcc 文件名 即可完成对文件的编译,文件名的后缀一定是要以.c结尾的才可以被gcc进行编译
- ./a.out 编译完成后会自动在当前路径下生成一个文件名为a.out的可执行文件,我们使用 ./a.out 执行它即可
- g++ 文件名 即可完成文件的编译,文件名的后缀必须是.cpp的形式g++才能进行编译
- ./a.out 编译完成后在当前路径下会自动生成一个a.out的可执行文件,我们使用 ./a/out 直接执行即可
三、gcc/g++编译器的执行步骤
gcc/g++编译器如何将我们的源文件生成可执行程序的呢?
即进行了如下四个步骤 预处理(预编译),编译,汇编,链接
在vscode下进行gcc编译器的演示讲解【c语言】预处理、编译、汇编、链接深度详解小编也已经早就整理出来了,详情请点击<—
- gcc和g++的执行步骤中的指令都是相同的,这里小编以linux中的gcc编译器的执行步骤中的指令为例进行讲解
知识补充:我们为什么可以在windows或linux上进行c/c++或其他形式的开发呢?
因为我们要进行的c/c++开发的环境不仅仅是指诸如vs,gcc,g++,更为重要的是有开发语言对应头文件和库文件,同时头文件和库文件会存放在系统的特定路径下
例如:预处理阶段中的头文件既然可以进行展开,那么说明在系统路径下一定有地方存放头文件,在预处理阶段将头文件的内容拷贝到源文件中,头文件的路径为/usr/include
1. 预处理
gcc -E 文件名 -o 预处理后的文件名(使用 .i 结尾),即可告诉编译器从现在开始进行程序的翻译,执行完预处理工作后就停下来
- 去掉注释
注释是写给开发者人员的自然对于程序的编译自然无用,所以编译器将对于编译阶段无用的注释去掉- 头文件的展开
头文件既然可以进行展开,那么说明在系统路径下一定有地方存放头文件,在预处理阶段将头文件的内容拷贝到源文件中- 条件编译
可以支持对代码的裁剪工作,例如应用的社区版和免费版其实就是应用了条件编译,使同一份代码经过条件编译后呈现出两种不同的状态- 宏替换
小编特别讲解一下这里的宏替换不进行语法检查,我们知道在编译阶段进行语法的检查,而宏替换是在编译阶段之前,即预处理阶段已经完成了宏替换,即预处理完之后由于宏已经被替换了,所以此时宏就没有了,自然在进行编译阶段又谈何对宏替换的语法检查呢?
- 我们可以看到,对比我们原来的test.c文件,将头文件进行展开后多出了800多行代码,并且进行了宏替换,去掉了注释,进行条件编译,这里进行条件编译时,由于我们并没有定义宏HELLO,所以裁剪了#if HELLO下的代码,保留了#else下的代码
- 并且我们还可以看到这里的代码仍然是c语言代码
3. gcc -E 文件名 -o 预处理后的文件名(使用 .i 结尾)-D直接加要进行定义宏,其实这里的宏定义也可以在源文件的外面,即使用指令-D直接加要进行定义宏
4. 观察,我们使用指令在源文件内部定义了HELLO宏之后,条件编译的结果就对应改变了
2. 编译
gcc -S 要进行编译的文件名(建议使用预处理后以 .i 为后缀的文件) -o 编译后的文件名(这里建议使用 .s 为后缀),即告诉编译器从现在开始进行翻译,当编译工作完成后,就停下来
- 语法,词法,语义检查
- 符号汇总(汇总文件内的全局变量名和函数名)
- 将c语言代码翻译成汇编代码
- 如下我们的c语言代码就被翻译成了汇编代码
3. 汇编
gcc -c 要进行汇编的文件名(这里建议使用编译后的.s文件) -o 汇编后的文件名(这里建议使用.o为后缀的文件名),告诉编译器开始进行程序的翻译,当汇编工作完成后,就停下来
这里注意我们生成的汇编后的文件名test.o又称为可重位目标二进制文件,简称目标文件(.obj文件),虽然是目标文件,虽然是二进制文件了,但是仍然不可以执行,因为它不具有可执行的能力,即使我们使用了chmod u+x test.o 给它加上了可执行权限,但是仍然不可以执行,因为它不具有可执行的能力,所以它不可执行
需要进行和库进行链接后生成可执行文件,这时候文件有了可执行的权限和能力,可以执行,关于库小编会在后文进行详细讲解
- 将汇编代码翻译成二进制指令(机器指令)
- 生成符号表
- vim 汇编后的文件名,当我们使用vim打开已经被翻译为二进制指令的文件后,发现全部都是乱码,这是正常的,因为vin是文本编辑器,它是用来查看文本文件的,当前我们打开的是二进制文件,所以是乱码
- od 汇编后的文件名,这时候我们要借助特定的工具 od 来进行打开二进制文件进行查看,尽管打开了,可是我们仍旧看不懂,这是正常的,因为这是给计算机机器看的
4. 链接
gcc 要进行链接的文件(这里建议使用执行完汇编后生成的.o文件) -o 链接后的文件名,将编译生成的可重定位目标二进制文件(目标文件)和库进行链接生成可执行程序
- 生成可执行文件或库文件
- 合并段表
- 符号表的合并和重定位
关于第二点和第三点小编在这里有讲,这里就不再重复讲解了详情请点击<—
- ./可执行文件名,即可执行可执行文件
这里小编进行介绍一下选项巧记忆方法,键盘左上角位Esc,对应选项中的ESc,前两个大写,最后一个小写即可
同时还有步骤中生成的文件名ios苹果移动端的操作系统,将o和s换一下,为iso对应到预处理,编译,汇编生成的文件名后缀即可
四、库
1. 库的介绍
上文小编已经讲到,在链接的时候会进行汇编生成的二进制文件和库进行链接,那么这个库具体是指的是什么呢?
并且拿我们的c语言程序中的printf函数来说,我们在程序中调用printf打印hello,#include头文件中是printf函数的声明,那么实现究竟是在哪里呢?没错,在库中,
- 在库中提供函数方法的实现,在c语言中即为c语言标准库
- 库的本质是文件,有其对应的路径在linxu中为(动态库)/usr/lib64/libc.so或(静态库)/usr/lib64/libc.a
库分为动态库和静态库,库有自己的命名风格,libname.so.xxx或libname.a.xxx这中间对应文件的name区域那么即为库的名,其中xxx为库的不同版本,例如c语言中的库name对应就为c,那么就为c标准库
- linux:.so(动态库) .a(静态库)
- windows:.dll(动态库) .lib(静态库)
- 系统默认只提供动态库,为/usr/lib64/libc.so,但是对于静态库/usr/lib64/libc.a系统默认不提供即没有进行安装,这时候我们就要自行去安装静态库或动态库
动态库
查看安装好之后的静态库
方法的实现其实就在库中
库其实是将源文件经过翻译,打包成为一个文件(不用提供太多的源文件,也达到了隐藏源文件的目的),库避免了一些经常性使用的函数实现的重复书写,节省工作,提高效率
你的软件=头文件提供声明+库提供函数的实现+你的代码
2. 我们的.o文件和库是如何进行链接的
库分为动态库(共享库)和静态库,那么对应有动态链接和静态链接
动态链接:
- 动态链接是在程序执行时由运行时的链接文件加载库,所以很多程序的运行都要依赖动态库的存在,所以动态库不能缺失,一旦缺失会造成很多程序无法运行,进而可能造成无法使用操作系统
静态链接:
- 编译器在使用静态库进行静态链接的时候,会将静态库的方法拷贝到目标程序中,需要使用哪些函数方法就将哪些函数方法拷贝到目标文件中,并不是将静态库的所有方法都拷贝到目标文件中,这一点经常被混淆,请读者友友们注意区分,此后程序的执行不再需要依赖静态库
在linux中,编译形成可执行程序,默认采用的链接方式是动态链接—动态库
- ldd 可执行程序 可以查看或打印一个程序运行所需的共享库
- 由于系统中默认都没有安装静态库,接下来我们安装一下c/c++静态库,这里小编使用了sudo提权,如何才能让普通用户进行sudo提权,小编已经在文章的开头有讲,不会的可以去看一下
- sudo yum install -y glibc-static 安装c静态库
- sudo yum install -y libstdc++-static 安装c++静态库
- 在linux中,如果想要按照静态链接方式形成可执行程序,需要添加static选项—提供静态库,其实编译器默认的链接方式是采用动态链接方式链接目标文件和库进而生成可执行程序,使用选项static其实是指定编译器使用静态链接的链接方式进行链接目标文件和库,进而生成可执行程序
观察一下静态链接方式由于是将库进行拷贝,所以占用空间明显大于动态链接(程序执行时由运行的链接文件进行加载库)方式
- 如果没有静态库,我们不能使用-static进行静态链接
- 如果没有动态库,只有静态库,并且编译器gcc可以找到静态库,此时编译器采用静态链接将我们的目标文件和库进行链接,因为当系统中存在动态库的时候,系统会优先采用动态链接,当不存在动态库的时候,编译器会再去看看系统中有没有静态库,如果有静态库则采用静态链接的方式,如果连静态库都没有则报错
- 同时在我们的可执行文件中,并不是所有的链接方式都是纯动态链接的,而是动态链接和静态链接混合的方式
- file 可执行程序,可以查看我们的可执行程序的链接方式
动态库的优缺点:
- 优点:动态库由于是共享库,所以可以有效节约空间(内存空间,磁盘空间,网络空间)
- 缺点:动态库一旦缺失会造成很多程序无法运行
静态库的优缺点:
- 优点:程序一旦链接完成形成了可执行程序,就不依赖库,可执行程序可以独立运行
- 缺点:体积大,比较消耗资源(内存空间,磁盘空间,网络空间)
五、debug和release
在linux中,编译器默认生成的可执行程序是release发布版本,即追求性能的版本
如果想要生成debug版本的可执行程序,就需要我们在使用gcc/g++进行编译的时候进行手动指定选项-g添加debug信息,使我们的可执行程序可以被执行追踪
通常debug版本由于添加了debug调试信息,通常都是比默认生成的release版本的所占用的空间大
- gcc 要进行编译的文件 -o 可执行文件名 -g
readelf -S 可执行文件名,可执行文件形成的时候不是无序的,而是有独特的格式,可执行程序有自己的二进制格式(elf格式),我们可以使用readelf -S 可执行文件名,来进行查看可执行文件的二进制格式
同时我们还可以借助管道,使用grep对二进制格式中的信息进行搜索,其中-i选项是忽略大小写进行查找,grep的使用请点击<—,由于test是release是发行版本,没有添加debug信息,所以无法查找到debug,test_debug是debug版本,添加了debug信息,所以可以查找到debug
总结
以上就是今天的博客内容啦,希望对读者朋友们有帮助
水滴石穿,坚持就是胜利,读者朋友们可以点个关注
点赞收藏加关注,找到小编不迷路!