1、程序设计重要概念
一个程序本质上都是由 bss段、data段、text段三个段组成。这三个小鬼,在裸机开发中非常重要。因为它们涉及到程序运行时内存大小的分配。?!先来看看它们究竟有什么特殊功能,是骡子是马,拉出来溜溜嘛。
Ⅰ、bss段
通常是用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零。为什么要清零,因为bss段属于静态内存分配,也就是说等到需要用到时才会在栈中分配内存空间。
Ⅱ、data段
用于存放在编译阶段(而非运行时)就能确定的数据,可读可写。也是通常所说的静态存储区,赋了初值的全局变量、常量和静态变量都存放在这个域。data段其实包含读写数据段和只读数据段。只读数据段存放了 const 修饰的变量
Ⅲ、text段
用于存放程序代码的区域,编译时确定,只读。更进一步讲是存放处理器的机器指令,当各个源文件单独编译之后生成目标文件,经连接器链接各个目标文件并解决各个源文件之间函数的引用,与此同时,还得将所有目标文件中的.text段合在一起,但不是简单的将它们“堆”在一起就完事,还需要处理各个段之间的函数引用问题。
2、连接脚本LDS
由于每个程序都由bss段、data段、text段组成,但是如何这些零散的段合成一个可执行文件。此时,就需要lds出马了。肯定又有疑问,lds是什么鬼啊?
lds属于脚本语言,也是有语法的。具体作用:指明text段、data段、bss段的存放地址以及运行地址。这里先不贴出代码。后续结合Makefile进行编译比较清楚。
3、Makefile
哈哈哈,怎么还有呢,单片机开发没有这么多要求啊!Makefile规定了如何编译工程文件,将所有的.c文件编译成可执行文件。其实Makefile还依赖于编译工具链。编译工具链了解gcc和arm-linux-gcc即可,前者编译的程序只能在x86上运行,后者编译的程序可以在arm板上运行。如何使用,后面结合例程会比较有印象。
4、常见汇编语法
接触过单片机都知道,代码运行是从main函数开始的,C语言是需要栈的,arm开发板是空白的,所以需要用汇编做一些初始化工作,然后调用main函数,进入C语言环境运行。
Ⅰ、基本语法
标号
操作码 操作数 1, 操作数 2, … ; 注释。
标号的作用是让汇编器来计算程序转移的地址。操作码是指令的助记符,它的前面必须有至少一个空白符, 通常使用一个“Tab”键来产生,汇编其实是机器指令的抽象,有兴趣可以了解指令集。不同指令对应不同的操作数,操作数1通常是指令结果的存储地址,通常是寄存器。具体代码不在这里贴出。可以参考杜春雷《ARM架构与编程》
5、基本环境搭建
开发最重要的还是平台,Java有Java平台和eclipse,单片机有keil平台,那么arm采用什么平台开发呢?采用Linux平台,?,那我们先安装个Linux系统吧,这里在Vmware虚拟机环境中安装Ubuntu。镜像地址:百问网->资料下载->002_JZ2440资料光盘_20180516(免费)->资料光盘->A盘->ubuntu-16.04.2-x64-100ask-for win7,8,10 64bit.zip;虚拟机:百问网->资料下载->002_JZ2440资料光盘_20180516(免费)->资料光盘->A盘->VMware-player-12.5.7-for win7,8,10 64bit.zip,安装Vmware之后选择打开虚拟机,即可进入Linux环境。
6、简单的Linux命令
ls:列出当前目录的文件
touch:创建新文件
rm:删除文件
mkdir:创建文件夹
rmdir:删除文件夹
mv:移动文件
copy:拷贝文件
cat:查看文件内容
gedit:程序图形编辑器
vi:vi编辑器
man:命令使用手册
info/help:帮助手册
这些命令都是可以带上参数的,使用时查看帮助手册,这里不贴出详细使用说明。
7、字节序
ARM寄存器有32位,均采用小字节序,也就是说对于0x12345678这样的数字,78是存放在低地址上的。
8、Linux命令进阶
Ⅰ、find命令
看名字就知道是跟查找有关系的命令。
格式:find 目录名 选项 查找条件
例子:find /work/001/ -name "test.txt"
条件支持通配符
注意:
1)如果没有指定查找目录,则为当前目录。
find . -name "*.txt" 其中.代表当前路径
find -name "*.txt" 没加路径,默认是当前路径下查找
2)find还有一些高级的用法,如查找最近几天(几个小时)之内(之前)有变动的文件
Ⅱ、grep命令
用来查找文件中符合条件的字符串
格式:grep [选项] [查找模式] [文件名]
例子:
grep -n "abc" test.txt 在test.txt中查找字符串abc
grep -rn "abc" * 在当前目录递归查找字符串abc
注意:
可以加入-w全字匹配。
r(recursive):递归查找
n(number):显示目标位置的行号
Ⅲ、file命令
识别文件类型
格式:file 文件名
例子:file ~/.bashrc 为ASCII 编码的text类型
Ⅳ、which/whereis命令
查询命令或者应用程序的所处位置
格式:which 命令名/应用程序名
例子:
which pwd 定位到/bin/pwd
which gcc 定位到/usr/bin/gcc
whereis pwd 查找到可执行程序的位置/bin/pwd和手册页的位置/usr/share/man/man1/pwd.1.gz
Ⅴ、gzip、bzip2命令
压缩或者解压缩
格式:gzip [选项] [文件名]
例子:gzip -l pwd.1.gz
gzip -k mypwd.1 得到了一个.gz结尾的压缩文件
gzip -kd 压缩文件名 该压缩文件是以.gz结尾的单个文件
常用选项:
-l(list) 列出压缩文件的内容
-k(keep) 在压缩或解压时,保留输入文件。
-d(decompress) 将压缩文件进行解压缩
1)如果gzip不加任何选项,此时为压缩,压缩完该文件会生成后缀为.gz的压缩文件
并删除原有的文件,所以说,推荐使用gzip -k来压缩源文件。
2)相同的文件内容,如果文件名不同,压缩后的大小也不同。
3)gzip只能压缩单个文件,不能压缩目录。
Ⅵ、tar命令
既然gzip,bzip不能压缩、解压多个文件,那么肯定有其他命令来完成。
格式:
1)、压缩
ar -czvf 压缩文件名 目录名
如: tar czvf dira.tar.gz dira
2)、查看
tar tvf 压缩文件名
如:tar tvf dira.tar.gz
3)、解压
tar xzvf 压缩文件名
tar xzvf 压缩文件名 -C 指定目录
如: tar xzvf dira.tar.gz 解压到当前目录
如: tar xzvf dira.tar.gz -C /home/book 解压到/home/book
tar常用选项:
-c(create) 表示创建用来生成文件包
-x:表示提取,从文件包中提取文件
-t可以查看压缩的文件。 -z使用gzip方式进行处理,它与”c“结合就表示压缩,与”x“结合就表示解压缩。
-j使用bzip2方式进行处理,它与”c“结合就表示压缩,与”x“结合就表示解压缩。
-v(verbose)详细报告tar处理的信息
-f(file)表示文件,后面接着一个文件名。
-C <指定目录> 解压到指定目录
Ⅶ、gcc与arm-linux-gcc编译工具链
一个程序从文本变成可执行文件的步骤:预处理、编译、汇编、链接
老生常谈了。
1)#开头的命令称为预处理命令,预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到一个.i文件中等待进一步处理。
2)编译就是把C/C++代码(比如上述的.i文件)翻译成汇编代码
3)汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现为ELF目标文件(OBJ文件)。反汇编是指将机器代码转换为汇编代码,这在调试程序时常常用到。
4)链接就是将上步生成的OBJ文件和系统库的OBJ文件、库文件链接起来,最终生成了可以在特定平台运行的可执行文件。
这些跟gcc/arm-linux-gcc有什么关系呢?
gcc -E -o 预处理文件.i 源文件.c #预处理
gcc -S -o 汇编文件.s 预处理文件.i #编译
gcc -c -o 二进制文件.o 汇编文件.s #汇编
gcc -o 可执行文件.bin 二进制文件.o #链接
注意:
gcc -lc 链接libc库文件,其中libc库文件中就实现了printf等函数
gcc -nostdlib 链接时请勿使用标准系统启动文件或库。没有启动文件
对于BootLoader、Linux内核,常用第二种,它们不需要标准库函数支持
Ⅷ、动态链接和静态链接
链接还有分类的:动态和静态,有什么区别呢?
动态链接:链接时采用动态库进行链接,生成的程序在运行时需要加载所需要的库,这样生成的程序体积比较小,但是必须依赖所需要的动态库。
静态链接:生成的程序包含程序运行所需要的全部库,可以直接运行,不过静态链接生成的程序体积较大。
对应gcc语法:
gcc -c -o hello.o hello.c
gcc -static -o hello_static hello.o