XX的学习日记(嵌入式)三——编译器背后的故事 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

XX的学习日记(嵌入式)三——编译器背后的故事

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:26

编译器背后的故事

  • 一、可执行程序是如何被组装的?
    • 1. 用 gcc 生成 .a 静态库和 .so 动态库
      • 1.1 编辑得到举例的程序:hello.h、hello.c和main.c
      • 1.2 将hello.c编译成.o文件;
      • 1.3由.o文件创建静态库
      • 1.4 在程序中使用静态库
      • 1.5由.o文件创建动态库文件
      • 1.6 在程序中使用动态库
    • 2.Linux下静态库.a与.so库文件的生成与使用
      • 2.1 编辑所需程序
      • 2.1 静态库.a文件的生成与使用
      • 2.2 共享库.so文件的生成与使用
    • 3. 将第一次学习内容的程序进行改编
      • 3.1 完成目标(1)
      • 3.2 完成目标(2)
  • 二、Gcc不是一个人在战斗。
    • 1. Linux GCC常用命令
      • 1.1 程序准备
      • 1.2 程序的简单编译
      • 1.3 程序的分步编译
    • 2. 比较hello.asm与C代码生成的可执行文件
      • 2.1 搭建环境:在Ubuntu上安装nasm

一、可执行程序是如何被组装的?

1. 用 gcc 生成 .a 静态库和 .so 动态库

我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
我们通过举例来说明在Linux中如何创建静态库和动态库,以及使用它们,在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。

1.1 编辑得到举例的程序:hello.h、hello.c和main.c

hello.c是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出"Hello XXX!"。hello.h为该函数库的头文件。main.c为测试库文件的主程序,在主程序中调用了公用函数hello。
hello.h
在这里插入图片描述
hello.c
在这里插入图片描述
main.c
在这里插入图片描述

1.2 将hello.c编译成.o文件;

无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件。
在系统提示符下键入以下命令得到hello.o文件。
gcc -c hello.c
通过ls命令查看是否生成了hello.o文件
在这里插入图片描述

1.3由.o文件创建静态库

静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令。
在系统提示符下键入以下命令将创建静态库文件libmyhello.a,并用ls命令查看结果
ar -crv libmyhello.a hello.o

在这里插入图片描述

1.4 在程序中使用静态库

静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件。
在程序3:main.c中,我们包含了静态库的头文件hello.h,然后在主程序main中直接调用公用函数hello。下面先生成目标程序hello,然后运行hello程序看看结果如何。
我们输入以下指令:gcc main.c libmyhello.a -o hello
在这里插入图片描述
我们删除静态库文件试试公用函数hello是否真的连接到目标文件 hello中了。
在这里插入图片描述
(这里我打错了一段指令,马了别介意: D)
程序照常运行,静态库中的公用函数已经连接到目标文件中了。

1.5由.o文件创建动态库文件

我们继续看看如何在Linux中创建动态库。我们还是从.o文件开始。
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。例如:我们将创建的动态库名为myhello,则动态库文件名就是libmyhello.so。用gcc来创建动态库。
在系统提示符下键入以下命令得到动态库文件libmyhello.so,并用ls命令查看
gcc -shared -fPIC -o libmyhello.so hello.o (-o不可少)
在这里插入图片描述

1.6 在程序中使用动态库

在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。我们先运行gcc命令生成目标文件,再运行它看看结果。
输入以下指令:gcc -o hello main.c -L. -lmyhello
在这里插入图片描述
这里出现了错误,我们看看错误提示,原来是找不到动态库文件libmyhello.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。我们将文件libmyhello.so复制到目录/usr/lib中,再试试。
在这里插入图片描述

2.Linux下静态库.a与.so库文件的生成与使用

如前面一样,我们先生成举例所需要的文件

2.1 编辑所需程序

A1.c
在这里插入图片描述
A2.c
在这里插入图片描述

A.h
在这里插入图片描述
test.c
在这里插入图片描述

2.1 静态库.a文件的生成与使用

(1) 生成目标文件(XXX.o)
指令如下:gcc -c A1.c A2.c
在这里插入图片描述
(2)生成静态库.a文件
指令如下:ar crv libafile.a A1.o A2.o
在这里插入图片描述
(3)使用.a 库文件,创建可执行程序(若采用此种方式,需保证生成的.a 文件与.c 文件保存在同一目录下,即都在当前目录下)
指令如下:

cpp gcc -o test test.c libafile.a
./test

在这里插入图片描述

2.2 共享库.so文件的生成与使用

(1)生成目标文件(XXX.o)(此处生成.o 文件必须添加"-fpic"(小模式,代码少),否则在生成.so文件时会出错)
指令:gcc -c -fpic A1.c A2.c
(2)生成共享库.so文件
指令:gcc -shared *.o -o libsofile.so
(3)使用.so 库文件,创建可执行程序
指令:gcc -o test test.c libsofile.s
在这里插入图片描述
当输入以下指令时:./test
发现出现错误:
在这里插入图片描述
原因与之前使用动态库的情况相同:找不到对用的.so文件,故需将对应 so 文件拷贝到对应路径。
指令
如下:sudo cp libsofile.so /usr/lib
在这里插入图片描述
同时可直接使用 gcc -o test test.c -L. -lname,来使用相应库文件
其中,
-L.:表示在当前目录下,可自行定义路径 path,即使用-Lpath 即可。
-lname:name:即对应库文件的名字(除开 lib),即若使用 libafile.a,则 name 为 afile;若要使用 libsofile.so,则 name 为 sofile。

3. 将第一次学习内容的程序进行改编

目标:
(1)除了x2x函数之外,再扩展写一个x2y函数(功能自定),main函数代码将调用x2x和x2y ;将这3个函数分别写成单独的3个 .c文件,并用gcc分别编译为3个.o 目标文件;将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小。
(2)将x2x、x2y目标文件用 ar工具生成1个 .so 动态库文件, 然后用 gcc将 main函数的目标文件与此动态库文件进行链接,生成最终的可执行程序,记录文件的大小,并与之前做对比。

3.1 完成目标(1)

(1)编辑所需程序
x2x.c
在这里插入图片描述
x2y.c
在这里插入图片描述
main.c
在这里插入图片描述
(2)将以上文件用gcc编译成.o文件
在这里插入图片描述
在这里插入图片描述
(3)将x2x.o和x2y.o用 ar工具生成 .a 静态库文件
在这里插入图片描述
(4)使用gcc将main.c文件与此静态库文件进行链接
在这里插入图片描述
(5) 运行xymain程序
在这里插入图片描述
在这里插入图片描述
记录文件大小为16888B

3.2 完成目标(2)

(1)将x2x.o、x2y.o文件用ar工具生成.so 动态库文件在这里插入图片描述
(2)用gcc将main.c文件与此动态库文件进行链接
在这里插入图片描述
(3)运行somain
在这里插入图片描述
记录文件大小为16888B


二、Gcc不是一个人在战斗。

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

1. Linux GCC常用命令

1.1 程序准备

在这里插入图片描述

1.2 程序的简单编译

这个程序的一步到位的编译指令是gcc test.c -o main
在这里插入图片描述

1.3 程序的分步编译

实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和连接(Linking)。

gcc -E test.c -o test.i //预处理
gcc -S test.i -o test.s //编译
gcc -c test.s -o test.o //汇编
gcc test.o -o test //连接

执行以上指令后生成以下文件,并查看运行结果
在这里插入图片描述

2. 比较hello.asm与C代码生成的可执行文件

2.1 搭建环境:在Ubuntu上安装nasm

相关案例查看更多