编译器背后的故事
日期: 2020-10-13 分类: 跨站数据测试 302次阅读
一、可执行文件是如何被组装的?
一个源程序到一个可执行程序的过程:预编译、编译、汇编、链接。 其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。 链接中,分为静态链接和动态链接。
二、用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)

{
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
标签:嵌入式
精华推荐