嵌入式C语言自我修养笔记1-ARM体系结构与编译运行

2023-05-16

目录

      • ARM 体系结构
        • ARM 体系结构
        • ARM 汇编指令
        • ARM 寻址方式
        • ARM 伪指令
        • C 与汇编混合编程
      • 程序编译链接与安装运行
        • 预处理过程
        • 编译过程
        • 链接过程
        • 程序安装
        • apt-get
        • 链接静态库
        • 动态链接
        • 共享库
        • 插件工作原理
        • Linux 内核模块运行机制
        • Linux 内核编译与启动分析

ARM 体系结构

ARM 体系结构

ARM 相对精简指令集 RISC 还有如下区别
● ARM 有桶型移位寄存器,单周期内可以完成数据的各种移位操作。
● 并不是所有的 ARM 指令都是单周期的。
● ARM 有 16 位的 Thumb 指令集,是 32 位 ARM 指令集的压缩形式,提高了代码密度
● 条件执行:通过指令组合,减少了分支指令数目,提高了代码密度。
● 增加了 DSP、SIMD/NEON 等指令。


除了用户模式是普通模式,剩下的几种工作模式都属于特权模式

ARM 处理器中的寄存器可分为通用寄存器和专用寄存器两种

寄存器 R0 ~ R12 属于通用寄存器
R0 ~ R3 通常用来传递函数参数
R4 ~ R11 用来保存程序运算的中间结果或函数的局部变量等
R12 常用来作为函数调用过程中的临时寄存器


R13 寄存器又称为堆栈指针寄存器(Stack Pointer,SP),用来维护和管理函数调用过程中的栈帧变化,R13 总是指向当前正在运行的函数的栈帧,一般不能再用作其他用途

R14 寄存器又称为链接寄存器(Link Register,LR),在函数调用过程中主要用来保存上一级函数调用者的返回地址

R15 又称为程序计数器(Program Counter,PC),CPU 从内存取指令执行,就是默认从 PC 保存的地址中取的

当前处理器状态寄存器(Current Processor State Register,CPSR)主要用来表征当前处理器的运行状态

在每种工作模式下,都有一个单独的程序状态保存寄存器(Saved Processor State Register,SPSR)


ARM 汇编指令

ARM 指令集属于 RISC 指令集,CPU 无法对内存里的数据直接操作,只能通过 Load/Store 指令来实现

ARM 存储访问指令中,我们经常使用的是 LDR/STR、LDM/STM 这两对指令
LDR/STR 指令用来在寄存器和内存之间输送数据

在寄存器之间传送数据,则可以使用 MOV 指令

很多 ARM 指令会使用第二个参数 operand2:可以是一个常数,也可以是寄存器+偏移的形式


几乎所有的 ARM 指令都可以根据 CPSR 寄存器中的标志位,通过指令组合实现条件执行

BEQ 指令表示两个数比较,结果相等时跳转
BNE 指令则表示结果不相等时跳转


主要的跳转指令
B label 跳转到标号 label 处
BL label 表示带链接的跳转
BX Rm 表示带状态切换的跳转。Rm 寄存器中保存的是跳转地址,要跳转的目标地址处可能是 ARM 指令,也可能是 Thumb 指令
BLX 是 BL 指令和 BX 指令的综合


ARM 寻址方式

此版块内容已在 LinuxC 一站式编程的笔记下记录,如有需要可直接前往指定文章阅览


ARM 伪指令

ARM 伪指令并不是 ARM 指令集中定义的标准指令,而是为了编程方便,各家编译器厂商自定义的一些辅助指令

LDR 伪指令的主要用途是将一个 32 位的内存地址保存到寄存器中
一般我们会在 LDR 伪指令前加一个等号,用来告诉编译器这是个伪指令


ADR 功能和 LDR 类似,但其为小范围的地址读取伪指令,底层使用相对寻址来实现,因此可以做到代码与位置无关
ADR 伪指令在编译时则通常会被 ADD 或 SUB 指令代替
ADR 则使用相对地址


C 与汇编混合编程

混合编程需要遵循这个原则: ATPCS (全称是 ARM-Thumb Procedure Call Standard)
核心内容就是定义了 ARM 子程序调用的基本规则及堆栈的使用约定等


程序编译链接与安装运行

预处理过程

#pragma 预处理命令可以设定编译器的状态,指示编译器完成一些特定的动作
#pragma pack([n]):指示结构体和联合成员的对齐方式。
#pragma message("string"):在编译信息输出窗口打印自己的文本信息。
#pragma warning:有选择地改变编译器的警告信息行为。
#pragma once:在头文件中添加这条指令,可以防止头文件多次编译。


预处理的完整操作

  1. 头文件展开,#include 的头文件展开到当前位置
  2. 宏展开,删除所有#define
  3. 条件编译,根据宏定义的条件选择要参与编译的分支代码
  4. 删除注释
  5. 添加行号和文件名标识
  6. 保留#pragma 命令

编译过程

编译过程即将高级语言变成低级语言的过程,汇编语言和二进制语言很相似

编译过程可分为六步

  1. 词法分析:词法扫描器从左到右逐字符扫描,名将其分解为最小单元 token
  2. 语法分析:通过对 token 进行解析,得到一个语法正确的语法树 AST
  3. 语义分析:对语法分析输出的各种表达式、语句进行检查
  4. 中间代码生成:转换语法树为中间代码,他是一个一维线性序列结构
  5. 汇编代码生成:使用汇编器将前一阶段生成的汇编文件翻译成目标文件
  6. 目标代码生成

语法分析工具在对 token 序列分析过程中,如果发现不能构建语法上正确的语句或表达式,就会报语法错误:syntax error

中间代码与平台无关,可以任意的在后续的流程中转换为 x86 平台或者 ARM 平台

汇编的流程主要包括词法分析、语法分析、指令生成等过程


符号表
汇编器会分析汇编语言中各个 section 的信息,收集各种符号,生成符号表,将各个符号在 section 内的偏移地址也填充到符号表内

重定位表:重定向符号关联的地址


链接过程

链接器将编译器生成的各个可重定位目标文件重新分解组装:
将各个目标文件的代码段放在一起,作为最终生成的可执行文件的代码段;
将各个目标文件的数据段放在一起,作为可执行文件的数据段

链接器会在可执行文件中创建一个全局的符号表,收集各个目标文件符号表中的符号,然后将其统一放到全局符号表中


符号决议:不同模块之间全局变量如命名一致就会造成变量污染,此时链接器会使用特殊的决议方法避免冲突

符号决议解决变量同名冲突的方法

  • 引入强弱符号:函数名、初始化的全局变量是强符号,而未初始化的全局变量则是弱符号
  • 在一个多文件的工程中,强符号不允许多次定义,否则就会发生重定义错误
  • 强符号和弱符号可以在一个项目中共存,当强弱符号共存时,强符号会覆盖掉弱符号

GUN C 编译器使用 __attribute__ 关键字来将强符号转换为弱符号

强符号对应强引用,弱符号对应弱引用
强引用时链接找不到定义,报未定义错误;弱引用时链接找不到定义, 不报错;


程序安装

DEBIAN 系(ubuntu、debian)安装包管理系统为 deb;RedHat(kail)系安装包管理系统为 rpm

按照以下步骤制作我们的第一个 deb 安装包

任选一个文件夹,创建源码 demo.c

#include <stdio.h>

int main(void){
  printf("123\n");
  return 0;
}

编译得到可执行文件 gcc -o hw.out demo.c

在当前文件夹下创建文件夹 hw,并根据以下树形结构创建对应的文件与文件夹
control 文件用来对 deb 包进行参数配置
hw 文件即我们刚刚编译好的可执行文件(这里需要把 hw.out 改名为 hw)

 hw
   ├── DEBIAN
   │   └── control
   └── usr
       └── local
           └── bin
               └── hw

control 文件进行简单的参数配置(注意 package 不能错!)

package:hw
version:1.0
architecture:i386
maintainer:wit
description:deb package demo

回到根目录下(此时和 hw 文件夹同级),打开终端,使用 dpkg 进行打包
dpkg -b hw/ hw_1.0_i386.deb

完毕,此时根目录下生成了打包好的文件 hw_1.0_i386.deb

简单的安装一下 sudo dpkg -i hw_1.0_i386.deb

此时,可执行文件 hw 就被默认安装到了 /usr/local/bin 文件夹下,相当于 ubuntu 的系统路径;
这意味着我们可以直接在任意路径下使用命令 hw 来执行该文件!


apt-get

apt-get 默认从 ubuntu 提供的主服务器下载包,这些包都经过官方检验后才上架供下载的

/etc/apt/source.list 存储着下载源使用的服务器,我们可以修改到当前位置最近的镜像节点

修改完毕镜像节点后需要对 apt 进行更新 sudo apt-get update
更新是为了获取可下载的软件列表,它存储在 /var/lib/apt/lists

apt-get 好处是可以处理依赖关系,就像 npm 下载时会把 A 库所依赖的 B 库也下载到 node_modules 文件夹内


链接静态库

静态库:编译时,链接器将引用的函数代码或者变量连接到可执行文件内部,与其组装在一起

动态库:在编译阶段不参与链接,在程序运行时才加载到内存参与链接


使用 ar 指令通过 c 源码打包成静态库
ar rcs demo.a demo.o

假设我们仅需要使用静态库中的一个方法,最好将该方法分离为一个单个静态库并对其进行链接,否则将所有方法变量写在一个静态库内会使得他们全部链接,造成冗余


动态链接

动态链接对静态链接做了一些优化:对一些公用的代码,如库,在链接期间暂不链接,而是推迟到程序运行时再进行链接

windows 下的动态链接库后缀为 dll,而 linux 则为 so


程序开始加载时,操作系统将控制权转交动态链接器,让他完成动态链接库加载与重定向,最后跳转欲运行的程序
(事实上,动态链接器也是一个动态链接库)

全局偏移表 GOT:每个应用程序将引用的动态库(绝对地址)符号收集起来,保存到该表中,这个表用来记录各个引用符号的地址


在这里插入图片描述


共享库

可执行文件依赖的共享库一般要放到库的默认路径下面,如/lib、/usr/lib

用户可以在 /etc/ld.so.conf 文件中添加自己的共享库路径

当然,你可以使用 LD_LIBRARY_PATH 来临时更改共享库路径
export LD_LIBRARY_PATH = /home/xxx/xxx


插件工作原理

插件的本质即为共享动态库
Linux 提供了专门的 API,支持显示加载和引用动态链接库

加载动态链接库
void *dlopen

获取动态对象地址
void *dlsym

关闭动态链接库
int dlclose(void *Handle)

动态库错误函数
const chat *dlerror(void)


Linux 内核模块运行机制

insmod 命令可以动态加载内核模块

内核模块文件后缀为 ko,它也是一个可重定位的目标文件

内核模块和动态库很相似,但前者是运行在内核态,后者运行于用户态


Linux 内核编译与启动分析

过于低层,不是你们嵌入式应用开发要学的,或者后续感兴趣再学,现在作者也没时间搁着说废话


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式C语言自我修养笔记1-ARM体系结构与编译运行 的相关文章

  • 【支线】输电杆塔识别-YOLO v5在Aidlux的部署

    目录 0 前言1 模型训练1 1 任务描述1 2 输电杆塔数据集采集1 3 输电杆塔数据集标注1 4 数据增强1 5 折腾1 6 训练1 7 测试 2 NX部署2 1 软硬件2 2 Tensor RT 优化推理2 3 ROS Topic发送
  • 程序员与厨师

    不管你信不信 反正我是信了 每一个程序员上辈子都是呆在厨房的厨子 好吧 你不信 我来证明给你看 1 下厨前 你得知道做的是早餐还是中晚餐 中晚餐的话 怎么也得走趟超市 如遇到好友聚会 怎么着也得做出一桌对得起朋友的饭菜 还有你得分析 朋友中
  • 用研扬科技的UP Square做软路由是不是杀鸡用牛刀啊?

    折腾了好几遍终于整踏实了 xff01
  • 炎炎夏日,看小Y重燃烈焰战火——Y450外接显卡

    xfeff xfeff 目录 前言 实际效果 预算VS结算 配件开箱 硬件连接 软件环境配置 xff08 重点 xff09 前言 我家小Y已经陪伴我4年多了 xff0c 四年里 xff0c 她带给我的欢乐是超值的 xff08 联保了4年多
  • 深度学习情感分类常用方法(综述)

    论文原文 xff1a Deep Learning for Sentiment Analysis A Survey 原文地址 xff1a https arxiv org ftp arxiv papers 1801 1801 07883 pdf
  • 嵌入式单片机之stm32串口你懂了多少!!

    stm32作为现在嵌入式物联网单片机行业中经常要用多的技术 xff0c 相信大家都有所接触 xff0c 今天这篇就给大家详细的分析下有关于stm32的出口 xff0c 还不是很清楚的朋友要注意看看了哦 xff0c 在最后还会为大家分享有些关
  • uC/OS-II 学习笔记之:消息邮箱

    更多原创 uC OS II学习笔记之 xff1a 系列 基础及嵌入式相关知识详解 xff0c 请访问可乐虎博客 xff1a http blog csdn net dcx1205 相信不会让您失望 xff01 xff01 一 消息邮箱的概念
  • uC/OS-II 学习笔记之:信号量、消息邮箱、消息队列之间的使用区别

    更多原创 uC OS II学习笔记之 xff1a 系列 基础及嵌入式相关知识详解 xff0c 请访问可乐虎博客 xff1a http blog csdn net dcx1205 相信不会让您失望 xff01 xff01 1 用信号量进行行为
  • Python3抓取糗百、不得姐、kanqu.com

    测试电脑配置有点低 xff0c 正常配置速度会比较快 有问题可以加群 xff1a 544471255 交流 使用必看 1 该代码使用Python3 6 43 版本 2 需要安装依赖库如下 可使用类似 pip install requests
  • 基于STM32F4实现FOC(磁场定向控制)一:电流采样和波形产生

    一 xff0e ADC的配置问题 1 GPIO初始化配置 开始ADC对应的GPIO口 xff0c 本驱动程序使用到五个GPIO xff0c 分别对应U V W三相电流及母线电压和温度采样 xff0c 统一配置为模拟输入 GPIO的配置代码如
  • 基于ADRC的FOC位置环控制

    ADRC位置环控制 ADRC介绍1 非线性跟踪微分器2 非线性ESO观测器3 非线性状态误差反馈控制律原理 NLSEF 4 调参流程 xff1a 1 调TD2 调ESO3 调NLSEF 5 基于ADRC的位置环设计ADRC框图基于ADRC的
  • 结构体和联合体在通信协议解析的应用

    在串口通信中 xff0c 我们往往会解析很多协议 xff0c 而且在协议中会出现不同数据类型的协议 xff1b 当然我们也可以把协议都定义成某一种数据格式 xff0c 但是那样会出现协议的复杂度 xff0c 但是不那样处理的话 xff0c
  • ubuntu14.04 怎么查看哪个串口才是有效的搜索?

    使用以上命令 xff0c 可以看见相对应的芯片型号 比如图中的 xff0c cp210x 对应的 ttyUSB0 FT232RL 对应 ttyUSB1 minicom 命令 xff1a CTRL 43 A 然后 O xff1b
  • 13_STM32Cubeide开发_RS485总线驱动

    一 485总线和硬件电路 典型的串行通讯标准是RS232和RS485 xff0c 它们定义了电压 阻抗等 xff0c 但不对软件协议给予定义 RS 485总线标准规定了总线接口的电气特性标准即对于2个逻辑状态的定义 xff1a 正电平在 4
  • 无人机系列之飞控算法

    一 无人机的分类 按飞行平台构型分类 无人机可分为固定翼无人机 旋翼无人机 无人飞艇 伞翼无人机 扑翼无人机等 图1 无人机平台构型 多轴飞行器multirotor 是一种具有三个以上旋翼轴的特殊的直升机 旋翼的总距固定而不像一般直升机那样
  • Java中==和equals的区别

    Java中 61 61 和equal的区别为 1 61 61 表示 判断2个变量或对象实例是否指向同一个内存空间 xff0c equals 表示 判断2个变量或对象实例所指向的内存空间的值是否相同 2 61 61 表示 对内存地址进行比较
  • Android注解(annotation)介绍及其应用

    我的新书 Android App开发入门与实战 已于2020年8月由人民邮电出版社出版 xff0c 欢迎购买 点击进入详情 文章目录 介绍自定义注解注解的应用 xff1a 反射注解的应用 xff1a APT其它 介绍 Annotation
  • 源代码管理的另类比较:TortoiseGit vs SourceTree

    文章目录 源代码得管理那就Git吧图形化Git管理软件对比暗色主题图形分支与提交历史仓库与工程代码改动对比分支切换提交到多个远端仓库编码UTF8与Ansi总结 Git提供网站免费部分对比GitHubGitee华为云总结 源代码得管理 以往用
  • kali Linux使用putty远程连接输入密码一直提示错误

    使用命令打开配置文件 xff1a leafpad etc ssh sshd config 修改AddressFamily any 前面的 删除修改PermitRootLogin yes 前面的 删除 修改PasswordAuthentica
  • ros安装并测试是否安装成功

    目录 一 xff0c 安装步骤二 xff0c 测试是否安装成功 一 xff0c 安装步骤 1 xff0c 首先前4项勾选 xff0c 然后源换成国内清华的源 2 xff0c 打开终端开始输入命令 xff1a span class token

随机推荐

  • C++ 双冒号::符号详解

    一 作用域符号 xff1a 作用域符号 的前面一般是类名称 xff0c 后面一般是该类的成员名称 xff0c C 43 43 为例避免不同的类有名称相同的成员而采用作用域的方式进行区分 例如 xff1a A B 表示两个类 xff0c 在
  • 嵌入式软件工程师前期职业生涯规划

    ARM 43 LINUX路线 xff0c 主攻嵌入式Linux操作系统及其上应用软件开发目标 xff1a xff08 1 xff09 掌握主流嵌入式微处理器的结构与原理 xff08 初步定为arm9 xff09 xff08 2 xff09
  • 【尚医通】微信扫码登录和手机号登录冲突问题解决思路

    尚医通 微信扫码登录和手机号登录冲突问题解决思路 问题描述 最近做尚医通遇到一个问题 xff0c 微信扫码登录和手机号登录在 特殊情况 下会发生冲突 xff0c 导致无法登录的问题 下面就描述一下几种情况 正常情况 xff1a 用户第一次一
  • GitHub awesome Resource

    各种Awesome技术资源的资源聚合 xff1a https github com sindresorhus awesome Contents PlatformsProgramming LanguagesFront End Developm
  • FreeRTOS ------ 栈、堆、任务栈

    1 任务的栈资源 xff08 创建任务分配的资源 xff0c 单位是4字节 xff09 来自 configTOTAL HEAP SIZE 定义的堆 xff0c 如果任务栈总量超过 configTOTAL HEAP SIZE xff0c 任务
  • STM32--微项目14-手撸I2C通讯、实现MPU6050六轴传感器控制

    一 微项目实现目标 xff1a STM32通过两个GPIO端口 xff0c 通过代码配置成I2C通讯状态 xff0c 通过I2C通讯与MPU6050进行信息交互 xff0c 包括配置MPU6050寄存器配置 获取MPU6050寄存器状态 x
  • ubuntu-查看文件系统

    ubuntu 查看文件系统 查看文件系统 deepfuture 64 deepfuture laptop df 文件系统 1K 块 已用 可用 已用 挂载点 dev sda1 75481116 3926204 67720600 6 tmpf
  • TypeError: Expected Ptr<cv::UMat> for argument ‘img‘

    使用opencv过程中报错 xff1a TypeError Expected Ptr for argument 39 img 39 请检查img参数是否是numpy数组 xff0c 以及其数据类型 dtype是否是np uint8 如果这两
  • TX2超详细,超实用刷机教程(亲测有效,所有步骤都是博主亲自实践过)

    本篇主要对TX2刷机流程以及刷机过程中遇到的坑和相应的解决办法做个记录 xff0c 以便再次刷机时能做个参考 如果你刚好收到TX2开发者套件 xff0c 还没有进行开箱 xff0c 那么请移步到我的前一篇博客进行TX2的开机测试 博客链接
  • MicroStrategy 简介 【Business Intelligent】

    下载地址 xff1a https www microstrategy com us resources microstrategy for students students Capabilities that power the Inte
  • crontab permission denied 解决办法,crontab 进程存在就不执行的方法

    crontab permission denied 出现场景 出现情况 xff0c sh文件在本地Win下面开发 xff0c 每次修改 xff0c 提交后在Linux上pull下来 xff0c 却发现x权限消失 导致crontab 里面定时
  • ROS入门之通信架构+实践问题+python版本切换解决

    运行起来后是什么样的通信结构 PR2机器人 这么多东西 xff0c 怎么管理进行 xff0c 并且怎么通信 节点管理器 xff08 作为管家管理进程 xff0c master xff09 node首先要向master注册 xff0c 之后就
  • matlab---s函数讲解之二连杆动力学仿真

    matlab虽然后simulink xff0c 但是再复杂系统的仿真的时候简单的simulink中模块不能满足要求 xff0c 因此需要自己建立s函数 xff0c 作为仿真中的一个模块 在控制系统中分为控制器和被控对象 matlab s函数
  • 全球定位系统的组成

    一 空间部分 1 GPS卫星 Block xff08 试验卫星 xff09 Block xff08 以下均为工作卫星 xff09 14天导航电文 xff0c 实施SA和AS的能力 Block A 180天导航电文 xff0c 卫星互相通信能
  • 前端疑难杂症集锦

    一 webpack打包时Cannot resolve module 39 fs 39 在webpack config js中添加 node fs 34 empty 34 二 typescript找不到fs模块 code npm instal
  • 基于ROS的语音控制机器人(二):上位机的实现

    文章目录 目录 文章目录 前言 一 准备工作 1 python工作环境 2 ros环境 3 QT designer 二 界面程序设计 1 界面设计 2 ui文件转py文件 三 上位机程序编写 1 具体思路 2 具体实现 3 遇到的问题 1
  • "指定的文件格式无法识别或为不支持的二进制"

    次奥 xff0c 你没有正确设置启动项目 转载于 https www cnblogs com tupx p 3701598 html
  • Linux安装MySQL8.0.16

    1 下载安装包 https www mysql com 2 安装MySQL 将下载好的安装包上传到服务器 然后解压 tar xvf mysql 8 0 16 el7 x86 64 tar gz 然后将解压目录重命名为mysql 8 0 16
  • 硬件中断和软件中断的区别

    中断 中断指当出现需要时 xff0c CPU暂时停止当前程序的执行转而执行处理新情况的程序和执行过程 即在程序运行过程中 xff0c 系统出现了一个必须由CPU立即处理的情况 xff0c 此时 xff0c CPU暂时中止程序的执行转而处理这
  • 嵌入式C语言自我修养笔记1-ARM体系结构与编译运行

    目录 ARM 体系结构ARM 体系结构ARM 汇编指令ARM 寻址方式ARM 伪指令C 与汇编混合编程 程序编译链接与安装运行预处理过程编译过程链接过程程序安装apt get链接静态库动态链接共享库插件工作原理Linux 内核模块运行机制L