Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >跨站数据测试

编译器背后的故事

一、可执行文件是如何被组装的?

一个源程序到一个可执行程序的过程:预编译、编译、汇编、链接。 其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。 链接中,分为静态链接和动态链接。

二、用gcc生成静态库和动态库

2.1 创建目录

先创建一个目录:
在这里插入图片描述

2.2 生成文件

在该目录下用vim、nano 或 gedit 等文本编辑器编辑生成所需要的 3 个文件:
在这里插入图片描述
三个文件的代码分别如下:
hello.c:

#ifndef HELLO_H
#define HELLO_H  
void hello(const char *name); 
#endif 

hello.h:

#include <stdio.h> 
void hello(const char *name) 
{printf("Hello %s!\n", name); }

main.c

#include "hello.h"
 int main() 
 {
 hello("everyone"); 
 return 0; 
 }

编译hello.c文件
在这里插入图片描述

2.3 创建静态库

用以下命令创建静态库:

# ar -crv libmyhello.a hello.o

在这里插入图片描述

2.4 在程序中使用静态库

使用如下命令:

gcc -c main.c                                \\先生成 main.o
gcc -o hello main.o libmyhello.a             \\再生成可执行文件

在这里插入图片描述

输入 ./hello运行程序
在这里插入图片描述
删除libmyhello.a,程序照常运行
在这里插入图片描述

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

删除刚才生成的文件:

rm libmyhello.a

然后输入:

gcc -shared -fPIC -o libmyhello.so hello.o  //生成动态文件库

(如果报错,可以用以下代码从新编译.o文件再尝试)

gcc -c -fpic hello.c

在这里插入图片描述

2.6 在程序中使用动态库

输入:

gcc -o hello main.c -L. -lmyhello     //生成目标文件
sudo mv libmyhello.so /usr/lib     //将文件 libmyhello.so 复制到目录/usr/lib
./hello

(如果是用的ubuntu16,则需要删除hello.o文件之后从新用gcc -fpic -c hello.c命令生成hello.o再执行gcc -o hello main.c -L. -lmyhello)
在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/20201012182408281.png#pic_center

在这里插入图片描述

三 、静态文件与动态文件对比

3.1 生成静态文件并记录大小

main.c,sub1.c,sub2.c三个文件代码如下:
main.c:

#include<stdio.h>
#include"sub1.h"
#include"sub2.h"
void main()
{
	float a=50,b=30,c,d;
	c=x2x(a,b);
        d=x2y(c); 
	printf("%lf\n",c);
        printf("%lf\n",d); 
}

sub1.c:

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

sub2.c:

#include<stdio.h>
float x2y(float x)
{
  float y;
  y=x*x;
}

把main.c,sub1.c,sub2.c分别编译为3个.o目标文件
再输入

ar -crv libmain.a sub1.o sub2.o   //生成静态文件库
gcc main.c libmain.a -o result    //mian.c与静态文件库连接

结果如下图:
在这里插入图片描述
记录文件大小:
在这里插入图片描述
在这里插入图片描述

3.2 生成动态文件并记录大小

删除静态库文件并输入:

gcc -shared -fPIC -o libmain.so sub1.o sub2.o    //生成动态文件库
gcc main.c libmain.so -o result       //与动态文件库连接

结果如下图
在这里插入图片描述
记录文件大小:
在这里插入图片描述
在这里插入图片描述
对比可知,动态文件库程序比静态文件库程序更大。

四、gcc及其编译工具中的软件

一组二进制程序处理工具,包括:addr2line、ar、objcopy、objdump、as、ld、 ldd、readelf、 size 等。这 一组工具 是开发和 调试不可 缺少的工具 ,分别简 介 如下:
(1) addr2line:用 来将程序 地址转 换成其所 对应的程 序源文 件及所对 应的代 码 行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对 应的源代码位置。
(2) as:主要用于汇编,有关汇编的详细介绍请参见后文。
(3) ld:主要用于链接,有关链接的详细介绍请参见后文。
(4) ar:主要用于创建静态库。为了便于初学者理解,在此介绍动态库与静态库 的概念:
…如果 要将 多个 .o 目标 文件 生成 一个 库文 件, 则存 在两 种类 型的 库, 一种 是 静态库,另一种是动态库。
…在 windows 中 静态 库是 以 .lib 为 后缀 的文 件 ,共 享库 是以 .dll 为 后缀 的 文 件 。 在 linux 中 静 态 库 是 以 .a 为 后 缀 的 文 件 , 共 享 库 是 以 .so 为 后 缀 的文件。
… 静 态 库 和 动 态 库 的 不 同 点 在 于 代 码 被 载 入 的 时 刻 不 同 。 静 态 库 的 代 码 在 编 译 过 程 中 已 经 被 载 入 可 执 行 程 序 , 因 此 体 积 较 大 。 共 享 库 的 代 码 是 在 可 执 行 程 序 运 行 时 才 载 入 内 存 的 , 在 编 译 过 程 中 仅 简 单 的 引 用 , 因 此 代 码 体 积 较 小 。 在 Linux 系 统 中 , 可 以 用 ldd 命 令 查 看 一 个 可 执 行 程 序 依 赖 的 共 享 库。
…如 果 一 个 系 统 中 存 在 多 个 需 要 同 时 运 行 的 程 序 且 这 些 程 序 之 间 存 在 共 享 库,那么采用动态库的形式将更节省内存。
(5) ldd:可以用于查看一个可执行程序依赖的共享库。
(6) objcopy:将一种对象文件翻译成另一种格式,譬如将.bin 转换成.elf、或 者将.elf 转换成.bin 等。
(7) objdump:主要的作用是反汇编。有关反汇编的详细介绍,请参见后文。
(8) readelf:显示有关 ELF 文件的信息,请参见后文了解更多信息。
(9) size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小 等,请参见后文了解使用 size 的具体使用实例。

4.1 gcc常用命令

创建一个文件夹并写一段简单代码,进行进行预处理,编译及汇编:
在这里插入图片描述

4.2 连接并查看一些属性

在这里插入图片描述

4.3分析ELF文件

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

在这里插入图片描述

4.4安装并使用nasm

使用 sudo apt-get install nasm安装nasm 并用nasm -version查看是否安装成功
在这里插入图片描述
把示例文件hello.asm复制到linux中,或者直接放到共享文件夹下:
在这里插入图片描述

对示例代码“hello.asm”编译生成可执行程序:

在这里插入图片描述
查看大小:
在这里插入图片描述
对比c代码:
在这里插入图片描述
显然,汇编代码占用内存小得多。

五、linux系统背后的代码库

5.1 curses的主要函数功能

一.全局变量
  WINDDW* curscr:当前屏幕
  WINDOW* stdscr:标准屏幕
二.函数说明
1.字符显示
  WINDOW* initscr()
 SCREEN* newterm(char *type, FILE *outfd, FILE *infd)
 初始化函数,对用户访问的每个终端都应该调用newterm,type是终端的名称,包括在$TERM中(如ansi, xterm, vt100等等) 。
2.方框和直线
  int border(ls, rs, ts, bs, tl, tr, bl, br)
  int wborder(win, ls, rs, ts, bs, tl, tr, bl, br)
  int box(win, vert, hor)
  这些函数在窗口的边界(或者win的边界)画上方框。在下面的表格中,读者将可以看到字符,以及它们的默认值。当用零去调用box(.)时将会用到这些默认值。在下面的图中读者可以看到方框中字符的位置

3.输出选项
  int  idlok(win, bf)
  void fdcok(win, bf)
  这两个函数为窗口使能或者关闭终端的insert/delete特征(idlok(.)针对一行,而fdcok(.)则针对字符)。(注:idcok(.)尚未实现)

5.2 在windows10中游客身份体验即将绝迹的远古时代的 BBS

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

打开cmd命令窗口输入 telnet bbs.newsmth.net进入bbs(一个用键盘光标控制的终端程序)。

在这里插入图片描述

在这里插入图片描述

5.3 安装curses库

使用以下代码安装curses库

sudo apt-get install libncurses5-dev

在这里插入图片描述
ubunt下,该库的头文件在 /usr/include ,库在/usr/lib/i386-linux-gnu/libc.so。

5.3 体验Linux 环境下C语言编译贪吃蛇游戏

在(http://www.linuxidc.com/Linux/2011-08/41375.htm)复制代码到ubuntu下,保存为mysnake.c
在这里插入图片描述
然后在该处打开终端输入输入

cc mysnake.c -lcurses -o mysnake  //生成可执行文件

在这里插入图片描述
然后输入./mysnake 及可运行贪吃蛇小游戏,如下图。

在这里插入图片描述

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: 关于GO语言,这篇文章讲的很明白

下一篇: 巨杉数据库完成数亿元D轮融资,引领金融级分布式数据库发展

精华推荐