1、入门
1.1常用指令
Shell 命令的格式
如下:
command -options [argument]
command: Shell 命令名称。
options:选项,同一种命令可能有不同的选项,不同的选项其实现的功能不同。
argument:Shell 命令是可以带参数的,也可以不带参数运行。
常用命令
1.1.1、目录信息查看命令 ls
ls [选项] [路径]
-a 显示所有的文件以及子目录,包括以“.”开头的隐藏文件。
-l 显示文件的详细信息,比如文件的形态、权限、所有者、大小等信息。
-t 将文件按照创建时间排序列出。
-A 和-a 一样,但是不列出“.”(当前目录)和“…”(父目录)。
-R 递归列出所有文件,包括子目录中的文件。
Shell 命令里面的参数是可以组合在一起用的,比如组合“-al”就是显示所有文件的详细信
息
1.1.2、目录切换命令
cd [路径]
路径就是我们要进入的目录路径,比如下面所示操作:
cd / //进入到根目录“/”下,Linux 系统的根目录为“/”,
cd /usr //进入到目录“/usr”里面。
cd … //进入到上一级目录。
cd ~ //切换到当前用户主目录
1.1.3 、当前路径显示命令 pwd
1.1.4 、系统信息查看命令 uname
uname [选项]
可选的选项参数如下:
-r 列出当前系统的具体内核版本号。
-s 列出系统内核名称。
-o 列出系统信息
1.1.5 、清屏命令 clear
1.1.6 、切换用户执行身份命令 sudo
sudo [选项] [命令]
选项主要参数如下:
-h 显示帮助信息。
-l 列出当前用户可执行与不可执行的命令
-p 改变询问密码的提示符。
1.1.7 、添加用户命令 adduser
adduser [参数] [用户名]
常用的参数如下:
-system 添加一个系统用户
-home DIR DIR 表示用户的主目录路径
-uid ID ID 表示用户的 uid。
-ingroup GRP 表示用户所属的组名。
1.1.8 、删除用户命令 deluser
deluser [参数] [用户名]
主要参数有:
-system 当用户是一个系统用户的时候才能删除。
-remove-home 删除用户的主目录
-remove-all-files 删除与用户有关的所有文件。
-backup 备份用户信息
同样的,命令“deluser”也要使用“sudo”来以 root 用户运行,
1.1.9 、切换用户命令 su
“sudo”,“su”命令格式如下:
su [选项] [用户名]
常用选项参数如下:
-c –command 执行指定的命令,执行完毕以后回复原用户身份。
-login 改变用户身份,同时改变工作目录和 PATH 环境变量。
-m 改变用户身份的时候不改变环境变量
-h 显示帮助信息
1.1.10 、显示文件内容命令 cat
cat [选项] [文件]
选项主要参数如下:
-n 由 1 开始对所有输出的行进行编号。
-b 和-n 类似,但是不对空白行编号。
-s 当遇到连续两个行以上空白行的话就合并为一个行空白行。
命令可组合
1.1.11 、显示和配置网络属性命令 ifconfig
ifconfig interface options | address
主要参数如下:
interface 网络接口名称,比如 eth0 等。
up 开启网络设备。
down 关闭网络设备。
add IP 地址,设置网络 IP 地址。
netmask add 子网掩码
1.1.12 、系统帮助命令 man
man [命令名]
比如我们要查看命令“ifconfig”的说明,输入“man ifconfig”即可
按“q”键退出到终端
1.1.13 、 系统重启命令 reboot
1.1.14 、系统关闭命令 poweroff
1.1.15 、软件安装命令 install
1.2 软件安装更新指令
1.2.1 、更新本地数据库
如果想查看本地哪些软件可以更新的话可以使用如下命令:
1.2.2 、检查依赖关系
有时候本地某些软件可能存在依赖关系,所谓依赖关系就是 A 软件依赖于 B 软件。通过如
下命令可以查看依赖关系,如果存在依赖关系的话 APT 会提出解决方案:
sudo apt-get check
1.2.3 、软件安装
这个是重点了,安装软件,使用如下命令:
sudo apt-get install package-name
上述命令是由“apt-get”和“install”组合在一起的,“package-name”就是要安装的软件名字,“apt-get”负责下载软件,“install”负责安装软件。
安装软件 Ubuntu 下的串口工具“minicom”,我们就可以使用如下命令:sudo apt-get install minicom
安装完成以后我们直接在终端输入如下命令打开 minicom 这个串口软件:minicom -s
1.2.4、更新软件
sudo apt-get upgrade package-name
sudo apt-get upgrade minicom
1.2.5 、卸载软件
sudo apt-get remove package-name
sudo apt-get remove minicom
1.3 文本编辑器
VI/VIM编辑器
先安装VIM。
新建文本文档 vim test.txt
i 在当前光标所在字符的前面,转为输入模式。
I 在当前光标所在行的行首转换为输入模式。
a 在当前光标所在字符的后面,转为输入模式。
A 在光标所在行的行尾,转换为输入模式。
o 在当前光标所在行的下方,新建一行,并转为输入模式。
O 在当前光标所在行的上方,新建一行,并转为输入模式。
s 删除光标所在字符。
r 替换光标处字符。
输入命令后要重新选择命令时按Esc
Ctrl+S是锁定终端 Ctrl+Q重新运行
指令模式下输入“:”进入底行模式。
x 保存当前文档并且退出。
q 退出。
w 保存文档。
q! 退出 VI/VIM,不保存文档。
搜索
指令模式下 /xx
1.4 文件系统
1.4.1 文件系统类型
Linux 下的文件系统主要有 ext2、ext3、ext4 等文件系统,也支持XFS、JFS、UFS 等,也支持 Windows 的 FAT 文件系统和网络文件系统 NFS 等
ext2 文件系统:
ext2 是 Linux 早期的文件系统,但是随着技术的发展 ext2 文件系统已经不推荐使用了
ext3 文件 系统:
支持大文件,特点如下:高可靠性,数据完整性,文件系统速度,数据转换
ext4 文件系统:
更佳的性能和可靠性,并且功能更丰富,ext4 向下兼容 ext3 和 ext2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ghkDUGHi-1576127806151)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574406578886.png)]
命令:df -T -h查看文件系统。
系统磁盘即为红框中的内容,ext4文件系统,大小略小于分配的磁盘容量,挂载点是/,即根目录
1.4.2 文件操作命令
1.4.2.1 创建新文件命令touch
touch [参数] [文件名]
若文件名不存在直接创建,若存在仅修改文件修改日期。
-a 只更改存取时间。
-c 不建立任何文件。
-d< 日期> 使用指定的日期,而并非现在日期。
-t< 时间> 使用指定的时间,而并非现在时间。
//cd ~ 切换终端至用户根目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O8CtSldJ-1576127806153)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574408577499.png)]
1.4.2.2 文件夹创建命令mkdir
mkdir [参数] [文件夹名目录名]
-p 如所要创建的目录其上层目录目前还未创建,那么会一起创建上层目录。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dGxrH5To-1576127806155)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574408131926.png)]
1.4.2.3 文件及目录删除命令rm
rm [参数] [目的文件或文件夹目录名]
-d 直接把要删除的目录的硬连接数据删成 0,删除该目录。
-f 强制删除文件和文件夹(目录)。
-i 删除文件或者文件夹(目录)之前先询问用户。
-r 递归删除,指定文件夹(目录)下的所有文件和子文件夹全部删除掉。
-v 显示删除过程。
删除文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ss0ikemS-1576127806157)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574408393021.png)]
删除文件夹
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jGUOEIYI-1576127806161)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574408420684.png)]
rm无法删除文件夹,需加上参数-rf,强制递归删除文件夹
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLBtAtx9-1576127806164)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574408479531.png)]
1.4.2.4 文件夹( 目录) 删除命令rmdir
rmdir [参数] [文件夹(目录)]
-p 删除指定的文件夹(目录)以后,若上层文件夹(目录)为空文件夹(目录)的话就将其一起
删除。
1.4.2.5 文件复制命令cp
cp [参数] [源地址] [目的地址]
-a 此参数和同时指定“-dpR”参数相同
-d 在复制有符号连接的文件时,保留原始的连接。
-f 强行复制文件,不管要复制的文件是否已经存在于目标目录。
-I 覆盖现有文件之前询问用户。
-p 保留源文件或者目录的属性。
-r 或-R 递归处理,将指定目录下的文件及子目录一并处理
下面一个指令例程,首先创建两个文件夹test1和test2,在test1中创建一个文件a.c,在test1中备份一个a.c命名为b.c,然后将ab复制到test2中。
cd ~ #用户目录
mkdir test1 test2 #创建两个文件夹
ls #查看是否创建成功
cd test1 #切换到test1目录下
touch a.c #创建文件a.c
ls #//查看是否创建成功
cp a.c b.c #//复制test1 路径下的a.c到test1 路径下,命名为b.c
ls #
cp *.c ../test2 #复制test1 路径下所有..文件到test1 目录上一级中的test2文件夹中
cd ../test2 #将当前路径切换至上一级目录中的test2目录下
ls #查看复制结果
复制文件夹
cd ~
cp -rf test2/ test3/ #复制
ls
cd test3
ls
cd ~
1.4.2.6文件移动命令mv
将一个文件或者文件夹移动到另外一个地方去,或者给一个文件或者文件夹进行重命名
mv [参数] [源地址] [目的地址]
-b 如果要覆盖文件的话覆盖前先进行备份。
-f 若目标文件或目录与现在的文件重复,直接覆盖目的文件或目录。
-I 在覆盖之前询问用户。
例程:在test1文件夹中创建一个c.c文件,然后将c.c重命名为d.c,最后移动到test2文件夹中
cd ~
cd test1
ls
touch c.c
ls
mv c.c d.c #重命名
ls
mv d.c ../test2 #移动
ls
cd ../test2
ls
1.4.3 文件压缩和解压缩
可在图形操作上完成。
命令行:命令行下进行压缩和解压缩常用的命令有三个:zip、unzip 和 tar
1.4.3.1zip
用于将一个或者多个文件压缩成一个.zip 结尾的文件
zip [参数] [压缩文件名.zip] [被压缩的文件]
-b< 工作目录> 指定暂时存放文件的目录。
-d 从 zip 文件中删除一个文件。
-F 尝试修复已经损毁的压缩文件。
-g 将文件压缩入现有的压缩文件中,不需要新建压缩文件。
-h 帮助。
-j 只保存文件的名,不保存目录。
-m 压缩完成以后删除源文件。
-n< 字尾符号> 不压缩特定扩展名的文件。
-q 不显示压缩命令执行过程。
-r 递归压缩,将指定目录下的所有文件和子目录一起压缩。
-v 显示指令执行过程。
-num 压缩率,为 1~9 的数值。
例程 将test2压缩
ls
zip -rv test2.zip test2 #//压缩 -rv 表示递归压缩并且显示压缩命令执行过程
ls
1.4.3.2 unzip
unzip 命令用于对.zip 格式的压缩包进行解压
unzip [参数] [压缩文件名.zip]
-l 显示压缩文件内所包含的文件。
-t 检查压缩文件是否损坏,但不解压。
-v 显示命令显示的执行过程。
-Z 只显示压缩文件的注解。
-C 压缩文件中的文件名称区分大小写。
-j 不处理压缩文件中的原有目录路径。
-L 将压缩文件中的全部文件名改为小写。
-n 解压缩时不要覆盖原有文件。
-P< 密码> 解压密码。
-q 静默执行,不显示任何信息。
-x< 文件列表> 指定不要处理.zip 中的哪些文件。
-d< 目录> 把压缩文件解到指定目录下。
unzip test.zip 解压到当前目录 解压到其他目录还不会用
1.4.3.3 tar
其他压缩格式的压缩和解压缩
tar [参数] [压缩文件名] [被压缩文件名]
-c 创建新的压缩文件。
-C< 目的目录> 切换到指定的目录。
-f< 备份文件> 指定压缩文件。
-j 用 tar 生成压缩文件,然后用 bzip2 进行压缩。
-k 解开备份文件时,不覆盖已有的文件。
-m 还原文件时,不变更文件的更改时间。
-r 新增文件到已存在的备份文件的结尾部分。
-t 列出备份文件内容。
-v 显示指令执行过程。
-w 遭遇问题时先询问用户。
-x 从备份文件中释放文件,也就是解压缩文件。
-z 用 tar 生成压缩文件,用 gzip 压缩。
-Z 用 tar 生成压缩文件,用 compress 压缩。
压缩
tar -vcjf test1.tar.bz2 test1 #//压缩为bz2格式 -vcjf 表示创建 bz2 格式的压缩文件,
tar -vczf test1.tar.gz test1 #//压缩为gz格式 -vczf 表示创建.gz 格式的压缩文件
解压
tar -vxjf test1.tar.bz2 #//-vxjf 用来完成.bz2 格式压缩文件的解压
tar -vxzf test2.tar.gz #//-vxzf 用来完成.gz 格式压缩文件的解压
1.4.4 文件查询和搜索
Linux 源码文件中查询某个文件是否存在,或者搜索哪些文件都调用了某个函数等
文件查询和搜索命令:find 和 grep
1 、命令 find
find 命令用于在目录结构中查找文件,其命令格式如下:
find [路径] [参数] [关键字]
路径是要查找的目录路径,如果不写的话表示在当前目录下查找,关键字是文件名的一部分,主要参数如下:
-name 按照文件名称查找,查找与 filename 匹配的文件,可使用通配符。
-depth 从指定目录下的最深层的子目录开始查找。
-gid< 群组识别码> 查找符合指定的群组识别码的文件或目录。
-group< 群组名称> 查找符合指定的群组名称的文件或目录。
-size< 文件大小> 查找符合指定文件大小的文件。
-type< 文件类型> 查找符合指定文件类型的文件。
-user< 拥有者名称> 查找符合指定的拥有者名称的文件或目录。
find /etc/ -name vim* #//搜索目录/etc 中以“vim”开头的文件
2 、命令 grep
在文件中搜索一串关键字,grep 就是完成这个功能的。grep 命令用于查找包含指定关键字的文件,如果发现某个文件的内容包含所指定的关键字,grep 命令就会把包含指定关键字的这一行标记出来
grep [参数] 关键字 文件列表
grep 命令一次只能查一个关键字,主要参数如下:
-b 在显示符合关键字的那一列前,标记处该列第 1 个字符的位编号。
-c 计算符合关键字的列数。
-d< 进行动作> 当指定要查找的是目录而非文件时,必须使用此参数!否则 grep 指令将回报信息并停止搜索。
-i 忽略字符大小写。
I.MX6U 嵌入式 Linux 驱动开发指南
-v 反转查找,只显示不匹配的行。
-r 在指定目录中递归查找。
目录/usr 下递归查找包含字符“Ubuntu”的文件
grep -ir "Ubuntu" /usr #//目录/usr 下递归查找包含字符“Ubuntu”的文件
1.4.5 文件类型
-普通文件,一些应用程序创建的,比如文档、图片、音乐等等。
d 目录文件。
c 字符设备文件,Linux 驱动里面的字符设备驱动,比如串口设备,音频设备等。
b 块设备文件,存储设备驱动,比如硬盘,U 盘等。
l 符号连接文件,相当于 Windwos 下的快捷方式。
s 套接字文件。
p 管道文件,主要指 FIFO 文件
1.4.6 用户权限管理
用户类型分为以下 3 类:
● 初次创建的用户,此用户可以完成比普通用户更多的功能。
● root 用户,系统管理员,系统中的玉皇大帝,拥有至高无上的权利。
● 普通用户,安装完操作系统以后被创建的用户。
用户相关信息可以在文件/etc/passwd 中查看
每个用户名后面都有两个数字, 第一个数字是用户的 ID,另一个是用户的 GID,也就是用户组 ID。 Ubuntu里面每个用户都属于一个用户组里面,用户组就是一组有相同属性的用户集合。
1.4.6.1 文件权限
一个文件通常有三种权限:读®、写(w)和执行(x),使用命令“ls -l”可以查看 。
-rw-rw-r-- 1 zuozhongkai zuozhongkai 0 12 月 25 20:44 test.c 为例
其中“-rw-rw-r–”表示文件权限与用户和用户组之间的关系,第一位表示文件类型,剩下的 9 位以 3 位为一组,分别表示文件拥有者的权限,文件拥有者所在用户组的权限以及其它用户权限。 后面的“zuozhongkai zuozhongkai”分别代表文件拥有者(用户)和该用户所在的用户组
-也是内容!! 第一位是-表示文件是普通文件,rw-是拥有者权限,-表示不可执行,若文件只写,则权限为-w-
●文件 test.c 的拥有者是用户 zuozhongkai,其对文件 tesst.c 的权限是“rw-”,也就是对该文件拥有读和写两种权限。
●用户 zuozhongkai 所在的用户组也叫做 zuozhongkai,其组内用户对于文件 test.c 的权限是“rw-”,也是拥有读和写这两种权限。
●其它用户对于文件 test.c 的权限是“r–”,也就是只读权限。
对于文件,可读权限表示可以打开查看文件内容,可写权限表示可以对文件进行修改,可执行权限就是可以运行此文件(如果是软件的话)。对于文件夹,拥有可读权限才可以使用命令 ls查看文件夹中的内容,拥有可执行权限才能进入到文件夹内部。
字母 | 二进制 | 八进制 |
---|---|---|
r | 100 | 4 |
w | 010 | 2 |
x | 001 | 1 |
权限 | 二进制数字 | 八进制数字 |
---|---|---|
— | 000 | 0 |
–x | 001 | 1 |
-w- | 010 | 2 |
-wx | 011 | 3 |
r– | 100 | 4 |
r-x | 101 | 5 |
rw- | 110 | 6 |
rwx | 111 | 7 |
字母 | 意义 |
---|---|
r | 可读权限 |
w | 可写权限 |
x | 可执行权限 |
a | 所有用户 |
u | 归属用户 |
g | 归属组 |
o | 其它用户 |
= | 具备权限 |
+ | 添加某权限 |
- | 去除某权限 |
我们想要修改其归属用户(zuozhongkai)对其拥有可执行权限,那么就可以使用: u+x
如果希望设置归属用户及其所在的用户组都对其拥有可执行权限就可以使用: gu+x。
1.4.6.2 权限管理命令
1、权限修改命令 chmod
命令“chmod”用于修改文件或者文件夹的权限,权限可以使用前面讲的数字表示也可以使用字母表示,命令格式如下:
chmod [参数] [文件名/目录名]
-c 效果类似“-v”参数,但仅回显更改的部分。
-f 不显示错误信息。
-R 递归处理,指定目录下的所有文件及其子文件目录一起处理。
-v 显示指令的执行过程。
结合上一节,调整一个文件的权限,使用数值方法,新创建的文件权限为 “-rw-rw-r–”,所有者可读写,所属组可读写,其他用户可读。改为"-rwxrw-rw-",所有者可读写可执行,所属组可读写其他用户可读写,
"-rw-rw-r–"三位一个数字对应 664 "-rwxrw-rw-"对应数字 766
指令 :chmod 766 test
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tzns5w10-1576127806167)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574474545335.png)]
ls -l test #//查看权限 -rw-rw-r--
chmod 766 test #//更改权限
ls -l test #//-rwxrw-rw-
chmod 664 test
ls -l test #//-rw-rw-r--
chmod u+x test #文件所有者增加可执行权限
ls -l test #//-rwxrw-r--
chmod g+x test #文件所属组增加可执行权限
ls -l test #// -rwxrwxr--
chmod o-r test #其他用户去除可读权限
ls -l test # // -rwxrwx---
改变文件夹下的文件权限
test文件夹下有a.c b.c c.c 权限都为-rw-rw-r–,改为 -rwxrwxrwx
ls -l text/
chmod 777 tset/
ls -l text/
2、文件归属者修改命令 chown
命令 chown 用来修改某个文件或者目录的归属者用户或者用户组,命令格式如下:
chown [参数] [用户名.<组名>] [文件名/目录]
其中[用户名.<组名>]表示要将文件或者目录改为哪一个用户或者用户组,用户名和组名用“.”隔开,其中用户名和组名中的任何一个都可以省略,命令主要参数如下:
-c 效果同-v 类似,但仅回报更改的部分。
-f 不显示错误信息。
-h 只对符号连接的文件做修改,不改动其它任何相关的文件。
-R 递归处理,将指定的目录下的所有文件和子目录一起处理。
-v 显示处理过程。
sudo chown root.root test 将文件test的归属用户和归属组都改为root
1.4.7 磁盘管理
1、磁盘分区命令
如果要对某个磁盘进行分区,可以使用命令 fdisk,命令格如下:
fdisk [参数]
主要参数如下:
-b<分区大小> 指定每个分区的大小。
-l 列出指定设备的分区表。
-s<分区编号> 将指定的分区大小输出到标准的输出上,单位为块。
-u 搭配“-l”参数,会用分区数目取代柱面数目,来表示每个分区的起始地址。
比如我要对 U 盘进行分区, 千万不要对自己装 Ubuntu 系统进行分区!!!
sudo fdisk /dev/sdb
p 显示现有的分区
n 建立新分区
t 更改分区类型
d 删除现有的分区
a 更改分区启动标志
w 对分区的更改写入到硬盘或者存储器中。
q 不保存退出。
2、格式化命令 使用命令
创建好一个分区以后,我们需要对其格式化,也就是在这个分区上创建一个文件系统, 下的格式化命令为 mkfs,命令格式如下:
mkfs [参数] [-t 文件系统类型] [分区名称]
主要参数如下:
fs 指定建立文件系统时的参数
-V 显示版本信息和简要的使用方法。
-v 显示版本信息和详细的使用方法。
比如我们要格式化 U 盘的分区/dev/sdb1 为 FAT 格式,那么就可以使用如下命令:
mkfs – t vfat /dev/sdb1
3、挂载分区命令 mount
比如我的 U 盘就一个分区,为/dev/sdb1,我们需要将/dev/sdb1 这个分区挂载到一个文件夹中,然后通过这个文件访问 U 盘。
mount [参数] -t [类型] [设备名称] [目的文件夹]
命令主要参数有:
-V 显示程序版本。
-h 显示辅助信息。
-v 显示执行过程详细信息。
-o ro 只读模式挂载。
-o rw 读写模式挂载。
-s-r 等于-o ro。
-w 等于-o rw。
4、卸载命令 当我们不在需要访问已经挂载的 盘,可以通过 umount将其从卸载点卸除,命令格式如
下:
umount [参数] -t [文件系统类型] [设备名称]
-a 卸载/etc/mtab 中的所有文件系统。
-h 显示帮助。
-n 卸载时不要将信息存入到/etc/mtab 文件中
-r 如果无法成功卸载, 则尝试以只读的方式重新挂载。
-t<文件系统类型> 仅卸载选项中指定的文件系统。
-v 显示执行过程。
常用流程
#第一步插入硬盘前检查已有硬盘
ls /dev/sd*
#第二步插入硬盘后再次检查已有硬盘,一般最后一个会是和之前的不一样的,也就是多出来的那个盘就是新加的。
ls /dev/sd*
#第三部挂载
sudo mount -t vfat /dev/sdc1 /mnt/tmp # 挂载需要root用户权限,-t为固定,vfat标识磁盘文件系统是fat格式,挂载的磁盘是/dev/sdc1,挂载在/mnt/tmp目录下。
#第四步进入挂载区
cd /mnt/tmp
#第五步验证是否挂载
ls
#注意创建目录之类的不要直接/,要加上/mnt/tmp,创建文件可以直接操作
#第六步卸载 注意卸载时不要cd在/mnt/tmp,这样文件是被占用着,没法卸载
cd /
sudo umount -t vfat /dev/sdc1
2、Linux C 编程入门
使用vim编辑器,编译时分开的。
2.2 GCC 编译器
2.2.1 gcc 命令
gcc [选项] [文件名字]
-c 只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o<输出文件名> 用来指定编译结束以后的输出文件名,如果使用这个选项的话 GCC 默
认编译出来的可执行文件名字为 a.out。
-g 添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编
译的时候生成调试所需的符号信息。
-O 对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进
行优化,这样产生的可执行文件执行效率就高。
-O2 比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。
2.3Makefile基础
写完三个文件联系起来的程序后,
方法一 :gcc main.c calcu.c input.c -o main //直接全部编译
方法二 :gcc -c main.c //只编译不链接
gcc -c input.c
gcc -c calcu.c
gcc main.o input.o calcu.o -o main //
若calcu.c文件修改,则只需要重新编译calcu.c文件
gcc -c calcu.c
gcc main.o input.o calcu.o -o main
方法二需要注意
1、如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序。
2、如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可。
3、如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且链接成可执行文件。
Makefile 区分大小写,创建文件
touch Makefile //在.c文件同一目录下
2.4 Makefile语法
2.4.1 Makefile格式规则
目标…... : 依赖文件集合……
命令 1
命令 2
……
例
main : main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
总结一下 Make 的执行过程:
1、 make 命令会在当前目录下查找以 Makefile(makefile 其实也可以)命名的文件。
2、当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。
3、当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标。
2.4.2 Makefile 变量
Makefile 中的变量都是字符串!类似 C 语言中的宏。
例,原代码如下:
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
以变量方式
object =main.o input.o calcu.o #定义 赋值
main: $(object) #$(object) 声明
gcc -o main $(object)
Makefile 中变量的引用方法是“$(变量名)”
变量名 = …
目标 : $(变量名)
gcc - main $(变量名)
赋值符 =
使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值
name = zzk
curname = $(name)
name = zuozhongkai
print:
@echo curname: $(curname)
以上程序中 输出的是zuozhongkai 在这里的=类似于引用
赋值符 :=
name = zzk
curname := $(name)
name = zuozhongkai
print:
@echo curname: $(curname)
以上程序中 输出的是 zzk在 :=只能使用前面已经定义好的量,不能使用后面的量。
赋值符?=
curname ?= zuozhongkai
上述代码的意思就是,如果变量 curname 前面没有被赋值,那么此变量就是“zuozhongkai”,如果前面已经赋过值了,那么就使用前面赋的值。
变量追加 +=
Makefile 中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串进
去,此时就要使用到符号“+=”,比如如下所示代码:
objects = main.o inpiut.o
objects += calcu.o
objects 就等于 main.o inpiut.o calcu.o
2.4.3 Makefile 模式规则
通过模式规则我们就可以使用一条规则来将所有的.c 文件编译为对应的.o 文件。
目标中的“%”表示对文件名的匹配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的文件,类似与通配符, a.%.c 就表示以 a.开头,以.c 结束的所有文件。
Makefile基础中的代码可改为以下形式
object =main.o input.o calcu.o
main:$(object)
gcc -o main $(object)
%o:%c #模式规则
#命令
clean :
rm *o
rm main
2.4.4 Makefile 自动化变量
自动化变量就是这种变量会把模式中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完,自动化变量只应该出现在规则的命令中。
自动化变量 | 描述 |
---|---|
$@ | 规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模 式中定义的目标集合。 |
$% | 当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件, 那么其值为空。 |
$< | 依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%” )定义的,那么 “$<”就是符合模式的一系列的文件集合。 |
$? | 所有比目标新的依赖目标集合,以空格分开。 |
$^ | 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件, “$^”会去除重复的依赖文件,值保留一份。 |
$+ | 和“$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。 |
$* | 这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模 式为 a.%.c,那么“$*”就是 test/a.test。 |
常用的三种: $@、 < 和 <和 <和^
模式规则中的程序补全为
object =main.o input.o calcu.o
main:$(object)
gcc -o main $(object)
%.o:%.c
gcc -c $< #自动化变量
clean :
rm *o
rm main
2.4.5 Makefile 伪目标
.PHONY : 目标
以clean为例,当文件夹中没有clean文件时,清除永远不会执行,但存在clean时就会执行,会导致误删除,加入伪目标后,只有运行make clean 才会执行清除,以上程序变为
object =main.o input.o calcu.o
main:$(object)
gcc -o main $(object)
.PHONY:clean #伪目标
%.o:%.c
gcc -c $<
clean :
rm *o
rm main
2.4.6 Makefile条件判断
语法
<条件关键字>
<条件为真时执行的语句>
endif
以及:
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
条件关键字有 4 个: ifeq、 ifneq、 ifdef 和 ifndef,
ifeq、 ifneq用来判断是否相同
ifdef 和 ifndef判断变量名是否为空
ifeq 用法如下:
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’ ,‘ <参数 2>’
ifeq “<参数 1>” , “<参数 2>”
ifeq “<参数 1>” , ‘<参数 2>’
ifeq ‘<参数 1>’ , “<参数 2>”
ifdef 和 ifndef 的用法如下:
ifdef <变量名>
3.4.7 Makefile 函数使用
Makefile 支持函数 ,不支持自定义。
函数的用法如下:
$(函数名 参数集合)
$(函数名 参数,参数,参数,)
调用函数和调用普通变量一样,使用符号“ ” 来 标 识 。 参 数 集 合 是 函 数 的 多 个 参 数 , 参 数 之 间 以 逗 号 “ , ” 隔 开 , 函 数 名 和 参 数 之 间 以 “ 空 格 ” 分 隔 开 , 函 数 的 调 用 以 “ ”来标识。参数集合是函数的多个参数,参数之间以逗号“,”隔开,函数名和参数之间以“空格”分隔开,函数的调用以“ ”来标识。参数集合是函数的多个参数,参数之间以逗号“,”隔开,函数名和参数之间以“空格”分隔开,函数的调用以“”开
常用函数
1.函数 subst 字符串替换
$(subst ,,
此函数的功能是将字符串
$(subst zzk,ZZK,my name is zzk) #my name is zzk变为my name is ZZK
2、函数 patsubst 用来完成模式字符串替换
使用方法如下:
$(patsubst ,,
此函数查找字符串
$(patsubst %.c,%.o,a.c b.c c.c) 将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的字符串为“a.o b.o c.o”。
3、函数 dir
函数 dir 用来获取目录,使用方法如下:
(
d
i
r
<
n
a
m
e
s
…
>
)
此
函
数
用
来
从
文
件
名
序
列
<
n
a
m
e
s
>
中
提
取
出
目
录
部
分
,
返
回
值
是
文
件
名
序
列
<
n
a
m
e
s
>
的
目
录
部
分
,
比
如
:
∗
∗
(dir <names…>) 此函数用来从文件名序列<names>中提取出目录部分,返回值是文件名序列<names>的目录部分,比如: **
(dir<names…>)此函数用来从文件名序列<names>中提取出目录部分,返回值是文件名序列<names>的目录部分,比如:∗∗(dir </src/a.c>)**
提取文件“/src/a.c”的目录部分,也就是“/src”
4、函数 notdir
函数 notdir 看名字就是知道去除文件中的目录部分,也就是提取文件名,用法如下:
(
n
o
t
d
i
r
<
n
a
m
e
s
…
>
)
此
函
数
用
与
从
文
件
名
序
列
<
n
a
m
e
s
>
中
提
取
出
文
件
名
非
目
录
部
分
,
比
如
:
∗
∗
(notdir <names…>) 此函数用与从文件名序列<names>中提取出文件名非目录部分,比如: **
(notdir<names…>)此函数用与从文件名序列<names>中提取出文件名非目录部分,比如:∗∗(notdir </src/a.c>)**
提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。
5、函数 foreach
foreach 函数用来完成循环,用法如下:
$(foreach , ,
此函数的意思就是把参数中的单词逐一取出来放到参数
中,然后再执行
包含的表达式。每次
会以空格隔开,最后当整个循环结束时,
函数 foreach 函数的返回值。
通配符“%wildcard$(wildcard PATTERN)
$(wildcard *.c)
.c %
3、Cortex-A7 MPCore 架构
3.1 Cortex-A 处理器运行模型
运行模型有九种
User、 FIQ、 IRQ、 Supervisor(SVC)、 Abort、 Undef和 System, Monitor ,Hyp
模式 | 描述 |
---|---|
User(USR) | 用户模式,非特权模式,大部分程序运行的时候就处于此模式。 |
FIQ | 快速中断模式,进入 FIQ 中断异常 |
IRQ | 一般中断模式。 |
Supervisor(SVC) | 超级管理员模式,特权模式,供操作系统使用。 |
Monitor(MON) | 监视模式?这个模式用于安全扩展模式,只用户安全。 |
Abort(ABT) | 数据访问终止模式,用于虚拟存储以及存储保护。 |
Hyp(HYP) | 超级监视模式?用于虚拟化扩展。 |
Undef(UND) | 未定义指令终止模式。 |
System(SYS) | 系统模式,用于运行特权级的操作系统任务 |
3.2 内核寄存器组
16 个 32 位的通用寄存器(R0~R15)供软件使用,前 15 个(R0~R14)可以用作通用的数据存储, R15 是程序计数器 PC,用来保存将要执行的指令。 ARM 还提供了一个当前程序状态寄存器 CPSR 和一个备份程序状态寄存器 SPSR, SPSR 寄存器就是 CPSR 寄存器的备份 。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gmbSwp98-1576127806169)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574728532027.png)]
每一种模式可见的寄存器包括 15 个通用寄存器(R0~R14)、一两个程序状态寄存器和一个程序计数器 PC。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLqf1cqv-1576127806170)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1574728342142.png)]
浅色部分是与usr模式共有的寄存器,蓝绿色背景是各个模式所独有的寄存器,低寄存器组(R0~R7)共享同一组物理寄存器。
CortexA 内核寄存器组成如下:
①、 34 个通用寄存器,包括 R15 程序计数器(PC),这些寄存器都是 32 位的。
②、 8 个状态寄存器,包括 CPSR 和 SPSR。
③、 Hyp 模式下独有一个 ELR_Hyp 寄存器。
3.2.1 通用寄存器
R0~R15 就是通用寄存器,通用寄存器可以分为一下三类:
①、 未备份寄存器,即 R0~R7。
②、 备份寄存器,即 R8~R14。
③、程序计数器 PC,即 R15。
1、未备份寄存器
未备份寄存器值R0~R7八个寄存器,所有模式下八个寄存器都是同一物理地址,所以在切换模式后寄存器中的数据会被破坏,因此不做特殊用途。
2、备份寄存器
R8R12这5个寄存器有两种物理地址,在除FIQ快速中断模式之外都是一个地址(Rx712),FIQ模式下是Rx_irq。快速中断模式要求快速执行,这样不使用同一地址会不影响其他模式,保证快速执行。
R13备份寄存器一共有 8 个物理寄存器,其中一个是用户模式(User)和系统模式(Sys)共用的,剩下的 7 个分别对应 7 种不同的模式。又称为SP,做为栈指针,基本每种模式一个地址,进入模式后SP会被指向该模式对应的地址。
R14 一共有 7 个物理寄存器,其中一个是用户模式(User)、系统模式(Sys)和超级监视模式(Hyp)所共有的,剩下的 6 个分别对应 6 种不同的模式。R14 也称为连接寄存器(LR) 。LR主要有两种用途,除此之外可作为普通寄存器。
1)每种模式使用LR来存放前子程序的返回地址,如果使用BL或者BLX调用函数,LR被设置为该子函数的返回地址,子函数中将LR的值赋给R15(PC)即可完成子函数返回。
2)发生异常后,该异常模式对应的R14寄存器被设置为该异常将要返回的地址。
3、程序计数器R15
R15 保存着当前执行的指令地址值加 8 个字节
R15中保存的是当前执行指令之后第第二条指令,当前指令之后的第一条指令正在被译码。
4、程序状态寄存器
所有的处理器模式都共用一个 CPSR 物理寄存器,因此 CPSR 可以在任何模式下被访问。 除了 User 和 Sys 这两个模式以外,其他 7 个模式每个都配备了一个专用的物理状态寄存器,叫做 SPSR(备份程序状态寄存器),当特定的异常中断发生时, SPSR 寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用 SPSR 中保存的值来恢复 CPSR。
SPSR 和CPSR 的寄存器结构相同
N(bit31):当两个补码表示的 有符号整数运算的时候, N=1 表示运算对的结果为负数, N=0表示结果为正数。
Z(bit30): Z=1 表示运算结果为零, Z=0 表示运算结果不为零,对于 CMP 指令, Z=1 表示进行比较的两个数大小相等。
C(bit29):在加法指令中,当结果产生了进位,则 C=1,表示无符号数运算发生上溢,其它情况下 C=0。在减法指令中,当运算中发生借位,则 C=0,表示无符号数运算发生下溢,其它情况下 C=1。对于包含移位操作的非加/减法运算指令, C 中包含最后一次溢出的位的数值,对于其它非加/减运算指令, C 位的值通常不受影响。
V(bit28): 对于加/减法运算指令,当操作数和运算结果表示为二进制的补码表示的带符号数时, V=1 表示符号位溢出,通常其他位不影响 V 位。
Q(bit27): 仅 ARM v5TE_J 架构支持,表示饱和状态, Q=1 表示累积饱和, Q=0 表示累积不饱和。
IT[1:0] (bit26:25): 和 IT[7:2] (bit15:bit10)一起组成 IT[7:0],作为 IF-THEN 指令执行状态。
J(bit24): 仅 ARM_v5TE-J 架构支持, J=1 表示处于 Jazelle 状态,此位通常和 T(bit5)位一起表示当前所使用的指令集,如表所示:
J | T | 描述 |
---|---|---|
0 | 0 | ARM |
0 | 1 | Thumb |
1 | 1 | ThumbEE |
1 | 0 | Jazelle |
GE[3:0](bit19:16):SIMD指令有效,大于或等于。
IT[7:2] (bit 15:10) 参考IT[1:0]。
E(bit9):大小端控制位,E=1表示大端模式,E=0表示小端模式。
A(bit8):禁止异步中断位,A=1表示禁止异步中断。
I(bit7):I=1禁止IRQ,I=0使能IRQ。
F(bit6):F=1禁止FIQ,F=0使能FIQ。
T(bit5):控制指令执行状态,表明本指令是ARM指令还是Thumb指令,通常和J(bit24)一起表明指令类型,参考J(bit24)位。
M[4:0]:处理器模式控制位,含义如表所示:
M[4:0] | 处理器模式 |
---|---|
10000 | User 模式 |
10001 | FIQ 模式 |
10010 | IRQ 模式 |
10011 | Supervisor(SVC)模式 |
10110 | Monitor(MON)模式 |
10111 | Abort(ABT)模式 |
11010 | Hyp(HYP)模式 |
11011 | Undef(UND)模式 |
11111 | System(SYS)模式 |
4、ARM 汇编基础
4.1 编程语法
由于我们使用的GCC交叉编译器,所以汇编代码要符合GNU语法,语句有三个可选部分
label: instruction @ comment
label:标号,表示地址位置,任何后面带:的标识符都会被认为是一个标号。
inrtruction 指令,也就是汇编指令或伪指令
@ 注释符,@之后的均为注释内容,也可以使用/**/
注意! ARM 中的指令、伪指令、伪操作、寄存器名等可以全部使用大写,也可以全部使用小写,但是不能大小写混用。
用户可以使用.section 伪操作来定义一个段
.section .testsection @定义一个 testsetcion 段
汇编系统预定义了一些段名:
.text 表示代码段。
data 初始化的数据段。
.bss 未初始化的数据段。
.rodata 只读数据段。
GNU 汇编同样也支持函数,函数格式如下:
函数名:
函数体
返回语句
GNU 汇编函数返回语句不是必须的
4.2 Cortex-A7 常用汇编指令
4.2.1 处理器内部数据传输指令
使用处理器做的最多事情就是在处理器内部来回的传递数据,常见的操作有:
①、将数据从一个寄存器传递到另外一个寄存器。
②、将数据从一个寄存器传递到特殊寄存器,如 CPSR 和 SPSR 寄存器。
③、将立即数传递到寄存器
指令 | 目的 | 源 | 描述 |
---|---|---|---|
MOV | R0 | R1 | 将 R1 里面的数据复制到 R0 中。 |
MRS | R0 | CPSR | 将特殊寄存器 CPSR 里面的数据复制到 R0 中。 |
MSR | CPSR | R1 | 将 R1 里面的数据复制到特殊寄存器 CPSR 里中。 |
1、 MOV指令
MOV指令用于将数据从一个寄存器拷贝到另外一个寄存器,或者将一个立即数传递到寄存器里面,使用示例如下:
MOV R0, R1 @将寄存器 R1 中的数据传递给 R0,即 R0=R1
MOV R0, #0X12 @将立即数 0X12 传递给 R0 寄存器,即 R0=0X12
2、 MRS 指令
MRS 指令用于将特殊寄存器(如 CPSR 和 SPSR)中的数据传递给通用寄存器,要读取特殊寄存器的数据只能使用 MRS 指令!使用示例如下:
MRS R0, CPSR @将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR
3、MSR 指令
MSR 指令和 MRS 刚好相反, MSR 指令用来将普通寄存器的数据传递给特殊寄存器,也就是写特殊寄存器,写特殊寄存器只能使用 MSR,使用示例如下:
MSR CPSR, R0 @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0
4.2.2 存储器访问指令
ARM 不能直接访问存储器,比如 RAM 中的数据,I.MX6UL 中的寄存器就是 RAM 类型的。用汇编来配置 I.MX6UL 寄存器的时候需要借助存储器访问指令,一般先将要配置的值写入到 Rx(x=0~12)寄存器中,然后借助存储器访问指令将 Rx 中的数据写入到 I.MX6UL 寄存器中。读取 I.MX6UL 寄存器也是一样的,只是过程相反。常用的存储器访问指令有两种:LDR 和STR,用法如表
指令 | 描述 |
---|---|
LDR Rd, [Rn , #offset] | 从存储器 Rn+offset 的位置读取数据存放到 Rd 中。 |
STR Rd, [Rn, #offset] | 将 Rd 中的数据写入到存储器中的 Rn+offset 位置。 |
1 、LDR
主要用于从储存加载数据到寄存器Rx中,LDR也可以将一个立即数加载到寄存器Rx中,加载立即数使用=,不使用#,LDR在嵌入式中最常见的就是读取CPU的寄存器值。例,读取地址为0X0209C004的寄存器
LDR R0,=0X0209C004 @将寄存器地址0X0209C004加载到R0,即R0=0X0209C004
LDR R1,[R0] @读取地址0X0209C004中的数据到R1寄存器中
2 、STR 指令
将数据写入到存储器中,与LDR相对应。例,将地址为0X0209C004的寄存器配置为0x20000002
LDR R0,=0X0209C004 @将寄存器地址0X0209C004加载到R0中,即R0=0X0209C004
LDR R1,=0x20000002 @R1保存要写入到寄存器的值,即R1=0x20000002
STR R1,[R0] @将R1中的值写入到R0中所保存的地址
LDR 和 STR 都是按照字进行读取和写入的,也就是操作的 32 位数据,
如果要按照字节、半字进行操作的话可以在指令“LDR”后面加上 B 或 H,
比如按字节操作的指令就是 LDRB 和STRB,按半字操作的指令就是 LDRH 和 STRH。
4.2.3 压栈和出栈指令
在进行现场保护的时候需要进行压栈(入栈)操作,恢复现场就要进行出栈操作。压栈的指令为 PUSH,出栈的指令为 POP,PUSH 和 POP 是一种多存储和多加载指令,即可以一次操作多个寄存器数据,他们利用当前的栈指针 SP 来生成地址,PUSH 和 POP 的用法如表
指令 | 描述 |
---|---|
PUSH < reg list > | 将寄存器列表存入栈中。 |
POP < reg list > | 从栈中恢复寄存器列表。 |
例 当前SP指向0x80000000,要将R0~R3、R12这五个寄存器压栈,处理器的堆栈是向下增长的
PUSH {R0~R3,R12} @将R0~R3和R12压栈
地址变化是以字为最小单位,即每次进出栈地址变化-+4。
以上执行完·后各寄存器数值所在地址为
R12 0x80000000
R3 0x80000000-4 7FFFFFFC
R2 0x80000000-8 7FFFFFF8
R1 0x80000000-12 7FFFFFF4
R0 0x80000000-16 7FFFFFF0
SP 0x80000000-20 =0x7FFFFFEC
要再将 LR 进行压栈
PUSH {LR} @将LR压栈
LR 0x7FFFFFEC
SP 0X7FFFFFE8
如果我们要出栈的话
POP {LR} @先恢复 LR
POP {R0~R3,R12} @在恢复 R0~R3,R12
出栈的就是从栈顶,也就是 SP 当前执行的位置开始,地址依次增大来提取堆栈中的数据到要恢复的寄存器列表中。
PUSH 和 POP 的另外一种写法是“STMFD SP!”和“LDMFD SP!”
STMFD SP!,{R0~R3, R12} @R0~R3,R12 入栈
STMFD SP!,{LR} @LR 入栈
LDMFD SP!, {LR} @先恢复 LR
LDMFD SP!, {R0~R3, R12} @再恢复 R0~R3, R12
4.2.4 跳转指令
①、直接使用跳转指令 B、BL、BX 等。(常用)
②、直接向 PC 寄存器里面写入数据。
指令 | 描述 |
---|---|
B < label > | 跳转到 label,如果跳转范围超过了+/-2KB,可以指定 B.W < label>使用 32 位版本的跳转指令, 这样可以得到较大范围的 跳转 |
BX < Rm> | 间接跳转,跳转到存放于 Rm 中的地址处,并且切换指令集 |
BL < label> | 跳转到标号地址,并将返回地址保存在 LR 中。 |
BLX < Rm> | 结合 BX 和 BL 的特点,跳转到 Rm 指定的地址,并将返回地 址保存在 LR 中,切换指令集。 |
B 和 BL 指令,因为这两个是我们用的最多的,如果要在汇编中进行函数调用使用的就是 B 和 BL 指令:
1、B指令
这是最简单的跳转指令,B 指令会将 PC 寄存器的值设置为跳转目标地址, 一旦执行 B 指令,ARM 处理器就会立即跳转到指定的目标地址
_start:
ldr sp,=0X80200000 @设置栈指针
b main @跳转到 main 函数
2 、BL指令
BL 指令相比 B 指令,在跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行,这是子程序调用一个基本但常用的手段。
例如中断函数,现场保护恢复和获取中断号由汇编实现,但是具体的中断服务函数时C语言实现的,由汇编跳转至C语言,服务完成后再由C语言跳转至汇编,由C语言跳转至汇编时需要跳转之前的地址,不然无法回到汇编中执行恢复现场。示例:
push {r0, r1} @保存 r0,r1
cps #0x13 @进入 SVC 模式,允许其他中断再次进去
bl system_irqhandler @加载 C 语言中断处理函数到 r2 寄存器中
cps #0x12 @进入 IRQ 模式
pop {r0, r1}
str r0, [r1, #0X10] @中断执行完成,写 EOIR
bl system_irqhandler就是执行C语言,处理完成后需要返回来继续后面的恢复。
4.2.5 算术运算指令
指令 | 计算公式 | 备注 |
---|---|---|
ADD Rd, Rn, Rm | Rd = Rn + Rm | 加法运算,指令为 ADD |
ADD Rd, Rn, #immed | Rd = Rn + #immed | … |
ADC Rd, Rn, Rm | Rd = Rn + Rm + 进位 | 带进位的加法运算,指令为 ADC |
ADC Rd, Rn, #immed | Rd = Rn + #immed +进位 | … |
SUB Rd, Rn, Rm | Rd = Rn – Rm | 减法 |
SUB Rd, #immed | Rd = Rd - #immed | … |
SUB Rd, Rn, #immed | Rd = Rn - #immed | … |
SBC Rd, Rn, #immed | Rd = Rn - #immed – 借位 | 带借位的减法 |
SBC Rd, Rn ,Rm | Rd = Rn – Rm – 借位 | … |
MUL Rd, Rn, Rm | Rd = Rn * Rm | 乘法(32 位) |
UDIV Rd, Rn, Rm | Rd = Rn / Rm | 无符号除法 |
SDIV Rd, Rn, Rm | Rd = Rn / Rm | 有符号除法 |
4.2.6 逻辑运算指令
指令 | 计算公式 | 备注 |
---|---|---|
AND Rd, Rn | Rd = Rd &Rn | 按位与 |
AND Rd, Rn, #immed | Rd = Rn &#immed | … |
AND Rd, Rn, Rm | Rd = Rn & Rm | … |
ORR Rd, Rn | Rd = Rd | Rn | 按位或 |
ORR Rd, Rn, #immed | Rd = Rn | #immed | … |
ORR Rd, Rn, Rm | Rd = Rn | Rm | … |
BIC Rd, Rn | Rd = Rd & (~Rn) | 位清除 |
BIC Rd, Rn, #immed | Rd = Rn & (~#immed) | … |
BIC Rd, Rn , Rm | Rd = Rn & (~Rm) | … |
ORN Rd, Rn, #immed | Rd = Rn | (w#immed) | 按位或非 |
ORN Rd, Rn, Rm | Rd = Rn | (wRm) | … |
EOR Rd, Rn | Rd = Rd ^ Rn | 按位异或 |
EOR Rd, Rn, #immed | Rd = Rn ^ #immed | … |
EOR Rd, Rn, Rm | Rd = Rn ^ Rm | … |