GCC背后的故事及GCC与库的爱情

一、用GCC生成.a静态库和.so动态库

1️⃣、创建一个实验文件夹,并在该文件夹下创建3个子程序hello.h、hello.c、main.c

在这里插入图片描述

程序hello.h内容如下:

#ifndefHELLO_H 
#defineHELLO_H 
voidhello(constchar*name); 
#endif//HELLO_H

程序hello.c内容如下:

#include<stdio.h> 
voidhello(constchar*name) 
{ 
printf("Hello%s!\n",name); 
}

程序main.c内容如下:

#include"hello.h" 
intmain() 
{ 
hello("everyone"); 
return0; 
}

2️⃣、将hello.c编译成.o文件

无论静态库,还是动态库,都是由.o文件创建的,所以我们必须将源程序hello.c通过gcc先编译成.o文件

gcc -c hello.c

通过以上命令得到hello.o文件,让我们来看看是否生成了

在这里插入图片描述

3️⃣、由.o文件创建静态库

静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a

接下来,我们创建静态库时就将用到ar命令

ar -crv libmyhello.a hello.o

通过以上命令得到静态库文件libmyhello.a,让我们继续看看是否生成

在这里插入图片描述

4️⃣、在程序中使用静态库

我们包含了静态库的头文件 hello.h,然后在主程序 main 中直接调用 公用函数 hello。下面先生成目标程序 hello,然后运行 hello 程序看看结果如何。

gcc -c main.c
gcc -o hello main.o libmyhello.a

用如上命令,先生成main.o,再生成可执行文件的方法,完成程序连接静态库的操作(在下面的动态库连接时也可以用同样的方法)

让我们来对静态库进行一个小测试,看看是否公用函数hello是否真的连接到了目标文件hello中了,让我们来删除掉静态库文件试试

在这里插入图片描述

程序仍然正常运行,看样子静态库中的公用函数已经连接到目标文件中了。

5️⃣、由.o文件创建动态库文件

动态库与静态库的文件名命名格式类似,同样是在动态库名增加前缀lib,但是其扩展名为.so

让我们用如下命令进行操作生成动态库文件libmyhello.so

gcc -shared -fPIC -o libmyhello.so hello.o

在这里插入图片描述

6️⃣、在程序中使用动态库

我们用同样的方式来使用动态库

在这里插入图片描述

操作后报错,原因是找不到动态库文件libmyhello.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。那么我们将libmyhello.so复制到目录/usr/lib中,再试试。

在这里插入图片描述

同样的,我们继续来做一个测试,删除.c和.h外的所有文件。

在这里插入图片描述

恢复成如图所示。再次创建静态库文件和动态库文件

在这里插入图片描述

然后我们运行gcc命令来使用函数库myhello生成目标文件hello,并运行hello。

在这里插入图片描述

和上面相同的错误,那么一样是默认连接到/usr/lib目录中,只需要将动态库文件复制到该目录下即可

当静态库和动态库同名时,gcc命令将优先使用动态库

二、静态库与动态库生成执行文件大小比较

1️⃣、创建一个work文件夹,来保存这次实验,在该文件夹中分别创建子文件sub1.c、sub2.c、main.c,用gcc 命令分别将三个子文件编译为.o的目标文件

sub1.c中内容如下:

#include<stdio.h>
flaot x2x(int a,int b)
{
	float c;
	c=a*b;
	return c;
}

sub2.c中内容如下:

#include<stdio.h>
float y2y(int a,int b)
{
	float c;
	c=a+b;
	return c;
}

main.c中内容如下:

#include<stdio.h>
int main()
{
	int a=3;int b=4;
	float c,d;
	c=x2x(a,b);
	d=y2y(a,b);
	printf("%f","%f",c,d);
	return 0;
}

在这里插入图片描述

(1)完成三个基本文件的编译后,将生成使用sub1.o和sub2.o文件创建静态库

在这里插入图片描述

(2)在程序中使用静态库

在这里插入图片描述

(3)创建动态库

在这里插入图片描述

(4)在程序中使用动态库

在这里插入图片描述

(5)比较两个可执行文件的大小

在这里插入图片描述

三、gcc编译器是如何编译的

(1)、创建一个test文件夹,在其中加入一个hello.c程序

hello.c内容如下:

#include<stdio.h>
int main()
{
	printf("hello!\n");
	return 0;
}

​ (2)程序的编译过程包含以下几个过程

①预编译(将源文件hello.c文件预处理生成hello.i)

在这里插入图片描述

②编译(将预处理生成的hello.i文件编译生成汇编程序hello.s)

在这里插入图片描述

③汇编(将编译生成hello.s文件汇编生成目标文件hello.o)

在这里插入图片描述

④链接(分为静态和动态链接,生成可执行文件)

在这里插入图片描述

(3)ELF文件的分析

一个典型的ELF文件包含下面几个段

①.text:已编译程序的指令代码段

②.rodata:ro代表read only,即只读数据(譬如常熟const)

③.data:已初始化的C程序全局变量和静态局部变量

④.bss:未初始化的C程序全局变量和静态局部变量

⑤.debug:调试符号表,调试器用此段的信息帮助调试

readelf -S hello

在这里插入图片描述

(3)反汇编ELF

可以使用objdump -D 对其进行反汇编

一、在Ubuntu下安装nasm

在Ubuntu18.04.5下打开搜狐浏览器,在其中https://www.nasm.us/pub/nasm/releasebuilds/2.14rc16/nasm-2.14rc16.tar.gz搜索以上链接,进行下载

随后,进行解压

cd 下载
tar zxvf nasm-2.14rc16.tar.gz

安装

cd nasm-2.14rc16/
./configure
make
sudo make install

查看安装是否成功

在这里插入图片描述

如图是安装好后的NASM版本

二、编译

编译汇编hello.asm文件,并于C代码的编译生成的程序大小进行比较

hello.asm内容如下:

; hello.asm 
section .data            ; 数据段声明
        msg db "Hello, world!", 0xA     ; 要输出的字符串
        len equ $ - msg                 ; 字串长度
section .text            ; 代码段声明
global _start            ; 指定入口函数
_start:                  ; 在屏幕上显示一个字符串
        mov edx, len     ; 参数三:字符串长度
        mov ecx, msg     ; 参数二:要显示的字符串
        mov ebx, 1       ; 参数一:文件描述符(stdout) 
        mov eax, 4       ; 系统调用号(sys_write) 
        int 0x80         ; 调用内核功能
                         ; 退出程序
        mov ebx, 0       ; 参数一:退出代码
        mov eax, 1       ; 系统调用号(sys_exit) 
        int 0x80         ; 调用内核功能


编译

nasm -f elf64 hello.asm

链接

 ld -s -o hello hello.o

在这里插入图片描述

大小比较

在这里插入图片描述

四、了解实际程序是如何借助第三方库函数完成代码设计

(一)、以游客身份体验一下即将绝迹的远古时代的BBS

在win10下,打开控制面板——>程序——>启用或关闭Windows功能,启动"telnet client" 和"适用于Linux的Windows子系统"如图
在这里插入图片描述

接下来我们以游客的身份进入

在这里插入图片描述

(二)、Linux环境下C语言编译实现弹球游戏

①在Ubuntu中用sudo apt-get install libncurses5-dev 安装curses库。

在这里插入图片描述

②新建一个文件夹,放人实现弹球游戏代码完成编译。内容参考curses库实现的弹球游戏

编译该.c文件

![在这里插入图片描述](https://img-blog.csdnimg.cn/20201017054531635.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lhbmdydW41OTk=,size_16,color_FFFFFF,t_70#pic_center
在这里插入图片描述

./game开始这个游戏,效果如下:

在这里插入图片描述

五、总结

过此次实验了解如何用 gcc 生成静态库(.a)和动态库(.so),更加了解了程序在编译的整个过程,有了崭新的体验,在第三方库函数方面有了更多的理解

六、参考资料

curses库实现的弹球游戏

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值