编译器背后的故事(嵌入式作业三)

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

一个源程序到一个可执行程序的过程:预编译、编译、汇编、链接。
其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。
链接中,分为静态链接和动态链接,本文主要是静态链接。
1.预编译:主要处理源代码文件中的以“#”开头的预编译指令。
2.编译:把预编译之后生成的xxx.i或xxx.ii文件,进行一系列词法分析、语法分析、语义分析及优化后,生成相应的汇编代码文件。
3.汇编:将汇编代码转变成机器可以执行的指令(机器码文件)。
4.链接
(具体要深入了解可以访问该下博客:https://blog.csdn.net/qq_39755395/article/details/78293733

1.用gcc将main1函数的目标文件与静态库文件进行链接,生成可执行程序,及用gcc生成静态库和动态库

1.首先先建立sub2.c文件:2.使用命令gedit sub2.c进入该文件进行编辑,保存退出:在这里插入图片描述上面程序代码如下:

#include<stdio.h>
float x2y(int a,int b)
{
	float d;
	d=a-b+1;
	return d;
}

3.进入我们之前写好的main1.c,进入编辑修改程序,保存退出:在这里插入图片描述
其中代码如下:

#include<stdio.h>
#include"sub1.h"
int main()
{
	float c,d;
	int a=5,b=10;
	c=x2x(a,b);
        d=x2y(a,b);
	printf("%f\n",c);
	printf("%f\n",d);
	return 0;
}

4.使用命令gcc -c 文件名.c分别编译并生成三个对应的.o文件:在这里插入图片描述
输入ls命令查看是否已经生成.o文件:在这里插入图片描述
5.然后输入途中命令将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件:在这里插入图片描述
用ls命令我们发现多出了一个静态库文件libsub.a如下:在这里插入图片描述
6.然后用gcc将main1函数的目标文件与此静态库文件libsub.a进行链接,输入命令如下:在这里插入图片描述
用ls命令发现生成了可执行文件main1:
在这里插入图片描述
7.输入./main1执行程序,得到输出结果:在这里插入图片描述
发现与程序内容执行出来的结果一致。
8.记录文件大小:在这里插入图片描述
9.gcc生成静态库和动态库已经在Ubuntu下完成,操作步骤太多太繁琐,就没有在博客内写出,需要细入了解,可以阅读、理解和学习材料“用gcc生成静态库和动态库.pdf”和“静态库.a与.so库文件的生成与使用.pdf”
a.静态库.a与.so库文件的生成与使用
b.用gcc生成静态库和动态库

2.生成.so动态库文件,用gcc将main1函数的目标文件与此动态库文件链接,生成可执行程序

1.首先先建立动态库libsub.so,然后用ls命令查看是否生成libsub.so文件:在这里插入图片描述
2.再将main1.c连接动态库并用ls查看是否生成可执行文件main,如下:在这里插入图片描述
3.然后输入./main运行生成的程序main,发现运行错误:在这里插入图片描述
4.解决方法:将libsub.so移动到/usr/lib后,再执行main,便可以正常执行:
在这里插入图片描述
得到的结果也正确。
5.查看main的大小:在这里插入图片描述
发现大小相差很小很小,只有几十个字节。

二.GCC编译工具中各软件用途及汇编语言

1.gcc编译及其编译为汇编代码

1.首先我们先用touch命令建立一个test.c文件,并进入编辑如下程序:
在这里插入图片描述

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

2.然后我们先进行预处理,输入以下命令:
在这里插入图片描述
(gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果,在本例中,预处理结果就是将stdio.h文件的内容插入到test.c中去了)

3.将其编译为汇编代码(预处理之后,可直接对生成的test.i文件编译,生成汇编代码):在这里插入图片描述
4.汇编为.o文件,需输入以下命令:
在这里插入图片描述
5.输入以下命令,将其链接为可执行文件:在这里插入图片描述
6.输入./test命令执行该文件:在这里插入图片描述
发现输出正确。

2.安装nasm的方法以及gcc,汇编命令操作,并编译运行示例代码

1.输入命令sudo apt install nasm,输入密码,等待nasm安装完毕:在这里插入图片描述
2.gcc中三种检错命令,为了使效果明显,我们故意将test.c文件进行修改,使之出现错误,再用以下命令进行检错(我们以去掉return后面的分号为例):
在这里插入图片描述
第一种检错方法:gcc -Werror 文件名.c -o 文件名在这里插入图片描述
我们发现它检验到了错误,并提示了位置。

第二种检验方法:gcc -pedantic 文件名.c -o 文件名在这里插入图片描述
错误仍检测到,且提示相同。

第三种方法:gcc -Wall 文件名.c -o 文件名
我们将程序错误改正,再检测试试在这里插入图片描述
发现不出现错误,无提示。
3.输入以下命令,编译为目标可执行文件:在这里插入图片描述
4.将目标文件与动态库进行链接:在这里插入图片描述
5.查看文件大小,可以用size+文件名查看,也可以在文件夹中查看文件属性:在这里插入图片描述
6.然后运用ldd+文件名 命令查看动态库链接:在这里插入图片描述
7.同样,将目标文件与静态库链接:在这里插入图片描述
8.用size+文件名查看静态库大小:
在这里插入图片描述
9.查看静态库链接:在这里插入图片描述
10.输入以下命令,进行反汇编操作:在这里插入图片描述
等待完成。
11.接下来我们先建立一个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         ; 调用内核功能

12.对文件进行nasm编译等操作,并ls命令,查看是否生成hello可执行文件:在这里插入图片描述
在这里插入图片描述
13.执行该文件:在这里插入图片描述
输出结果与我们程序中编写的一样,正确执行。
14.现在来比较以下两个可执行文件的大小:在这里插入图片描述
15.比较图如下:在这里插入图片描述

三.如何借助第三方库函数完成代码设计

1.curses函数的基本概念及其几个基本功能

1.curses函数的基本概念:
termios缺点,转义处理
提供与终端无关的字符处理方式
可以管理键盘
控制字符输入/输出的格式
支持多窗体管理

curses vs. ncurses
源文件包含头文件curses.h
编译时加 –lcurses选项
gcc program.c −o program −lcurses
gcc −I/usr/include/ncurses program.c −o program −lncurses
curses配置情况的检查
查看头文件:ls −l /usr/include/*curses.h
查看库文件:ls −l /usr/lib/*curses.*
cureses工作于屏幕、窗口和子窗口上
屏幕:正在写的设备,占据设备上的全部可用显示面积
窗口
curses窗口(称为stdscr):至少存在一个,与物理屏幕的尺寸相同
其他窗口:尺寸小于屏幕窗口,可以重叠
子窗口:必须包含在父窗口内

2.curses函数的几个基本功能:

输出到屏幕:

 1 int addch(const chtype char_to_add);
 2 int addchstr(chtype *const string_to_add);    //当前位置添加字符(串)
 3 
 4 int printw(char *format, ...);   //类似与printf
 5 int refresh(void);    //刷新物理屏幕
 6 int box(WINDOW *win_ptr, chtype vertical, chtype horizontal);   //围绕窗口绘制方框
 7 int insch(chtype char_to_insert);   //插入一个字符(已有字符后移)
 8 int insertln(void);   //插入空白行
 9 int delch(void);
10 int deleteln(void);   //删除字符和空白行
11 
12 int beep(void);   //终端响铃
13 int flash(void);   //闪烁
从屏幕读取字符;

1 chtype inch(void);  //返回光标位置字符
2 int instr(char *string);  //
3 int innstr(char *string, int numbers);  //将返回内容写入字符数组中
清除屏幕;

int erase(void);   //在屏幕的每个位置写上空白字符
int clear(void);    //使用一个终端命令来清除整个屏幕,内部调用了clearok来执行清屏操作,(在下次调用refresh时可以重现屏幕原文)
int clrtobot(void);   //清除光标位置到屏幕结尾的内容
int clrtoeol(void);    //清除光标位置到该行行尾的内容
移动光标;

int move(int new_y, int new_x);    //移动stdcsr的光标位置
字符属性(指对字符设置加粗,反色显示等);

预定义的属性:A_BLINK, A_BOLD, A_DIM, A_REVERSE, A_STANDOUT, A_UNDERLINE.

int attron(chtype attribute);
int attroff(chtype attribute);   //启用或关闭某属性
int attrset(chtype attribute);
int standout(void);
int standend(void);          //这两个表示更加通用的强调模式,通常映射为反白显示

2.体验一下即将绝迹的远古时代的BBS (一个用键盘光标控制的终端程序)

1.打开控制面板:在这里插入图片描述
2.进入程序之中,并点击Windows功能:在这里插入图片描述
在这里插入图片描述
3.启用 “telnet client” 和"适用于Linux的Windows子系统"用于后面使用在这里插入图片描述
在这里插入图片描述
选择之后确定,需要重启电脑。
4.然后我们打开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net,便可以以游客身份体验即将绝迹的远古时代的BBS :在这里插入图片描述
以上便是进入的界面。

3.安装curses库及头文件库文件的存放目录

1.安装curses库:在Ubuntu中输入命令 sudo apt-get install libncurses5-dev等待安装完毕即可。在这里插入图片描述
2.头文件和库文件分别被安装在/usr/include/和/usr/lib/中,输入ls +该目录名称,即可显示里面的文件。在这里插入图片描述
在这里插入图片描述

4.用gcc编译生成一个终端游戏,体会curses库如何被链接和使用

1.创建一个新的c文件并进入编辑:在这里插入图片描述
2.写好程序后保存退出:在这里插入图片描述
3.编译我们写好的贪吃蛇程序,然后用ls命令检测是否已经生成可执行文件:在这里插入图片描述
4.然后用命令./tanchishe即可进入贪吃蛇游戏进行玩耍(*符号代表贪吃蛇,@符号代表食物):在这里插入图片描述
附上贪吃蛇程序编写和介绍来源网址:贪吃蛇

四.小结

通过以上的实践和操作,加深了我对Ubuntu使用的兴趣,以及对更多命令的熟悉和掌握运用,也了解了一些新的函数库以及他们的相关功能,深化了我对Linux系统的了解和Ubuntu的使用,尤其是通过设计程序在Ubuntu下面试玩小游戏更是让我对Ubuntu产生了更大的兴趣,收益颇丰!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值