一.可执行程序是如何被组装的
一个源程序到一个可执行程序的过程:预编译、编译、汇编、链接。
其中,编译是主要部分,其中又分为六个部分:词法分析、语法分析、语义分析、中间代码生成、目标代码生成和优化。
链接中,分为静态链接和动态链接,本文主要是静态链接。
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产生了更大的兴趣,收益颇丰!