Ubuntu16.04下可执行文件的组装、GCC编译器背后的故事及第三方库的运用

摘要

本文主要介绍了在Ubuntu16.04系统下,用GCC生成静态库和动态库;接着介绍了GCC编译器背后的故事,比较了汇编与.C文件生成可执行文件的大小;然后通过第三方库curses来编写终端小游戏;最后总结。


一、静态库与动态库文件的生成及使用

1、可执行程序组装过程

其组装过程可以分为以下四个步骤:预处理、编译、汇编、链接

预处理:又叫预编译,是完整编译过程的第一个阶段,在正式的编译阶段之前进行。其具体功能 1、展开所有的宏定义,处理所有的条件编译 2、处理#include预编译指令,将被包含的文件插入该预编译指令的位置。3、删除所有注释 4、添加行号和文件标识 5、保留#pragma 编译器指令

编译:件进行一系列词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化后,产生相应的汇编代码文件。

汇编:将编译产生的汇编代码文件转变成可执行的机器指令,并生成可重定位目标程序的.o文件,该文件为二进制文件,字节编码是机器指令。

链接:分为静态链接和动态链接,通过链接器将多个目标文件和库文件链接在一起生成一个完整的可执行程序。

2、仿实部分过程与心得

step1:构建如下函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

step2:编译生成.o文件

在这里插入图片描述

step3:创建静态库

在这里插入图片描述

step4:使用静态库

在这里插入图片描述

在这里插入图片描述

step5:使用动态库

在这里插入图片描述

这时可以看到报错,该问题是译.o文件的时候,没有加参数 -fPIC,重新编译并加上 -fPIC,则可通过

在这里插入图片描述

之后再使用动态库

在这里插入图片描述
在这里插入图片描述

执行时会出现如上错误,因为连接是当前目录的动态库,现在只要把.so文件赋值到/usr/lib中就可以解决

注意:要以管理员身份运行哦

之后便可正常运行了

在这里插入图片描述

3、设计运用

step1:编写代码

在这里插入图片描述

修改主函数:

在这里插入图片描述

setp2:生成.o文件

在这里插入图片描述

step3:创建静态库

在这里插入图片描述

step4:使用静态库并执行

在这里插入图片描述
在这里插入图片描述

step5:查看大小

可以用 :

ls -lht

在这里插入图片描述

step6:创建、使用动态库并执行

在这里插入图片描述

同样的错误,上面已经说过重复操作即可

在这里插入图片描述
在这里插入图片描述

step7:查看大小

4、总结

可以看到静态库最后生成的执行文件要比动态库要大,静态库再程序编译时会被连接到目标代码中,而动态库在程序编译时并不会被连接到目标代码中,所以,静态库会比动态库稍微大一些。


二、GCC编译器背后的故事

1、仿实心得

GCC 的意思也只是 GNU C Compiler 而已。经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言;它现在还支持 Ada 语言、C++ 语言、Java 语言、Objective C 语言、Pascal 语言、COBOL 语言,以及支持函数式编程和逻辑编程的 Mercury 语言,等等。而 GCC 也不再单只是 GNU C 语 言编译器的意思了,而是变成了 GNU Compiler Collection 也即是 GNU 编译器家族的意思了。另 一方面,说到 GCC 对于操作系统平台及硬件平台支持,概括起来就是一句话:无所不在。

GCC并不是一个人在战斗,其实它还有一堆队友

Binutils:

一组二进制程序处理工具,包括:addr2line、ar、objcopy、objdump、as、ld、 ldd、readelf、 size 等。
(1) addr2line:用 来将程序 地址转 换成其所 对应的程 序源文 件及所对 应的代码行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对应的源代码位置。
(2) as:主要用于汇编。
(3) ld:主要用于链接。
(4) ar:主要用于创建静态库。
(5) ldd:可以用于查看一个可执行程序依赖的共享库。
(6) objcopy:将一种对象文件翻译成另一种格式,譬如将.bin 转换成.elf、或 者将.elf 转换成.bin 等。
(7) objdump:主要的作用是反汇编。
(8) readelf:显示有关 ELF 文件的信息。
(9) size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等。

2、仿实过程

step1:构建函数之间编译

在这里插入图片描述
在这里插入图片描述

step2:将步骤拆开一步步进行

1、预处理:

gcc -E test.c -o test.i

2、编译为汇编语言:

gcc -S test.i -o test.s

3、汇编:

gcc -c test.s -o test.o

4、连接:

gcc test.o test

可以看到一步直接编译过程可是由如此多的步骤构成!

3、as汇编编辑器

step1:在ubutu中安装nasm

as汇编编译器针对的是AT&T汇编代码风格,Intel风格的汇编代码则可以用nasm汇编编译器编译生成执行程序。运行如下代码:

sudo apt install nasm
step2:将编辑好的汇编文件直接复制到文件夹

step3:代码内容

在这里插入图片描述

step4:生成.o文件

step5:生成可执行文件并运行

step6:创建相同功能的.c文件可执行文件hello1比大小

可以看到汇编生成的可执行文件比.c文件生成的可执行文件要小的多!


三、借助第三方函数完成代码设计

1、光标库curses的主要函数功能

curses是一个在Linux下广泛应用的图形函数库,可以在终端内绘制简单的图形用户界面。使得原本黑黑的屏幕变成更好看的图形。下面我就专门介绍一下curses的主要函数功能

函数 功能
initscr() 初始化curses和tty
endwin() 关闭curses并重置tty
move(y,x) 将游标移至x,y位置
getyx(win,y,x) 得到目前游标的位置
clear() ad erase 将整个屏幕清除
echichar(ch) 显示某个字元
addch(ch) 在当前位置画字符ch
mvaddch(x,y,ch) 在(x,y)上显示某个字元

等,这里不再一一列举

2、感受即将绝迹的BBS

step1:打开控制面板–>程序–>启动或关闭Windows功能,启动’telnet client’和‘适用于Linux的Windows子系统’。如下:

在这里插入图片描述
在这里插入图片描述

step2:使用快捷键WIN+R打开cmd命令窗口,输入

~telnet bbs. newsmth.net

结果如下:
在这里插入图片描述

3、安装curses库

在Ubuntu终端环境下输入

sudo apt-get install libncurses5-dev

命令安装具体结果如下:

在这里插入图片描述

一般而言,用户安装库位置在: /usr/lib中;而头文件一般在/usr/include/中,在目录下查看如下

在这里插入图片描述

4、gcc编译生成终端游戏

先编写简单的贪吃蛇程序,部分代码如下:

在这里插入图片描述

代码来源:http://www.inuxidc.com/linux/2011-08/41375.htm

执行代码:

cc tcs.c-lcurses-o tcs

执行结果如下(*即为贪吃蛇,@为目标):

是不是很有趣呢,你也可以借助函数库去编写更多的小游戏

5、总结

借助第三方函数可以实现很多有趣的功能,在某些时候也可以大大减少你的工作量。可以从自己设计一些小游戏入手,不断提高自己的能力。

四、总结

1、通过对静态库和动态库分别的操作,使得我们对可执行文件是如何被组装的有了更深层次的认识,静态库与动态库不同的工作方式决定了在不同的场合可以运用不同的形式

2、在使用gcc编译器同时也要知道它背后的故事,并不是只有gcc编译器自己在运作。而不同的编译器又如汇编编译器生成可执行文件的大小也会不同

3、第三方库在当今编程过程中广为应用,熟练调用第三方库能够减少很多工作量,高效得编程又是有谁不想要的呢?

猜你喜欢

转载自blog.csdn.net/lee_goi/article/details/109116816