目录
ARM架构补充
一,程序状态寄存器
二,处理器工作模式
三,异常处理
四,指令流水线
汇编语言
一,什么是汇编
二,汇编怎么编
三,ARM汇编指令集
四,数据处理指令
五,立即数
六,函数的写法
七,代码演示
ARM架构补充
一,程序状态寄存器
在ARM架构中,程序状态寄存器主要用于存储处理器的状态信息,主要包括以下两种:
1. 当前程序状态寄存器(Current Program Status Register,CPSR):
- 基本信息:这是一个32位的寄存器,在ARM处理器中用于存储当前程序的状态信息,是ARM程序状态寄存器中最核心的部分。
- 具体功能:
- 处理器模式指示:CPSR的低5位(bit4~bit0)用于指示当前处理器的工作模式,例如用户模式(User)、快速中断模式(FIQ)、外部中断模式(IRQ)、特权模式(Supervisor)、数据访问中止模式(Abort)、未定义指令中止模式(Undefined)、系统模式(System)等。不同的模式具有不同的权限和功能,操作系统和应用程序可以根据需要切换处理器模式来实现特定的操作。
- 条件码标志:存储最近一次算术或逻辑运算的结果状态,包括负位(N)、零位(Z)、进位位(C)和溢出位(V)等。这些标志位可以被条件执行指令用来判断是否执行某条指令。例如,如果想要在某个数为零的条件下执行一条指令,就可以通过判断Z标志位来决定。
- 中断使能控制:包含中断禁止位,用于控制处理器对中断的响应。例如,I位用于普通中断的禁止或使能,F位用于快速中断的禁止或使能。当这些位被设置为1时,相应类型的中断被禁止;当为0时,中断被使能。
- 指令集信息:部分位用于指示当前处理器正在执行的指令集,例如区分ARM指令集、Thumb指令集等。
2. 保存程序状态寄存器(Saved Program Status Register,SPSR):
- 基本信息:SPSR也是32位的寄存器,每个异常模式都有对应的SPSR。
- 具体功能:当处理器进入异常模式时,CPSR的值会被自动保存到相应异常模式的SPSR中。当异常处理完成后,再将SPSR的值恢复到CPSR中,从而使处理器回到之前的状态继续执行程序。这样可以确保在异常处理过程中不会丢失之前程序的状态信息。
综上所述,ARM架构的程序状态寄存器对于处理器的运行状态监控、模式切换、中断处理以及程序的正确执行都起着至关重要的作用。
二,处理器工作模式
ARM处理器有7种工作模式:
1. 用户模式(User Mode,usr):
- 这是正常的用户程序执行模式,是ARM处理器的非特权模式。
- 在该模式下,应用程序只能访问自己的资源,不能访问受操作系统保护的系统资源以及其他应用程序的资源,对内存、I/O组件和标志等的访问都受到限制。
- 用户模式是应用程序最常用的模式,当操作系统将控制权交给应用程序时,处理器就处于用户模式。
2. 快速中断模式(Fast Interrupt Request Mode,fiq):
- 用于处理快速中断,主要针对对时间要求比较紧急的中断请求。常用于高速数据传输及通道处理等场景,例如处理一些需要快速响应的外部设备的中断。
- 在快速中断模式下,处理器会优先处理快速中断请求,并且拥有一些专门的寄存器,以便更快地处理中断,减少中断处理的延迟和开销。
3. 外部中断模式(Interrupt Request Mode,irq):
- 用于处理一般情况下的中断请求,是一种普通的中断模式。
- 当外部设备产生中断信号时,处理器会自动进入该模式来处理中断。在该模式下,处理器可以访问系统资源来处理中断事件,但相较于快速中断模式,其优先级较低。
4. 管理模式(Supervisor Mode,svc):
- 也称为超级用户模式,是操作系统使用的保护模式。
- 当用户模式下的程序需要访问受保护的系统资源或请求操作系统的服务时,会通过软件中断(SWI)进入管理模式。在该模式下,程序可以执行一些特权操作,如进行系统初始化、管理硬件资源等。
5. 数据访问终止模式(Data Abort Mode,abt):
- 当数据或指令预取终止时进入该模式,例如访问非法的内存地址、访问没有权限读取的内存地址等情况。
- 该模式可用于处理存储器故障、实现虚拟存储器和存储器保护等功能。当进入该模式后,处理器会采取相应的措施来处理异常情况,例如报告错误、进行错误恢复等。
6. 未定义指令中止模式(Undefined Instruction Mode,und):
- 当处理器执行未定义的指令时会进入该模式。这种情况可能发生在程序试图执行一条处理器不支持的指令,或者指令的编码格式不正确等情况下。
- 该模式可用于支持硬件协处理器的软件仿真,当遇到未定义的指令时,可以在该模式下进行相应的处理,例如模拟硬件协处理器的行为或报告错误。
7. 系统模式(System Mode,sys):
- 是一种特权模式,运行具有特权的操作系统任务。
- 系统模式和用户模式共用一套寄存器,但系统模式比用户模式具有更高的权限。操作系统的一些特权任务可以使用这个模式访问一些受控的资源。
除了用户模式外,其他六种模式均为特权模式。特权模式可以访问一些受保护的系统资源和寄存器,并且可以自由地切换处理器模式。而用户模式不能直接切换到其他模式,必须通过产生异常或软中断等方式来进入特权模式。
三,异常处理
在 ARM 架构中,异常处理是指当处理器遇到特定的事件或错误情况时,暂停当前程序的执行,转而执行相应的异常处理程序,以处理异常情况并恢复正常的程序执行。以下是关于 ARM 异常处理的详细介绍:
一、异常类型
1. 复位(Reset):
- 当处理器上电或复位引脚被触发时产生复位异常。这是一种最高优先级的异常,用于将处理器初始化到一个已知的状态。
- 复位异常会使处理器跳转到特定的复位地址开始执行程序,通常这个地址是由硬件决定的。在复位异常处理程序中,一般会进行硬件初始化、设置处理器模式、初始化内存和栈等操作。
2. 未定义指令(Undefined Instruction):
- 当处理器执行到一条未定义的指令时产生此异常。这可能是由于程序中出现了错误的指令编码或者试图执行一个处理器不支持的指令。
- 未定义指令异常可以用于软件仿真扩展指令集或处理错误的指令执行情况。在异常处理程序中,可以根据具体情况进行相应的处理,例如模拟未定义指令的行为或者报告错误。
3. 软件中断(Software Interrupt,SWI):
- 软件中断是由程序通过执行特定的指令(如 SWI 指令)主动触发的异常。它通常用于请求操作系统的服务或执行特权操作。
- 软件中断异常处理程序可以根据软件中断号来确定具体的请求,并执行相应的服务函数。例如,在操作系统中,应用程序可以通过软件中断来请求分配内存、打开文件等操作。
4. 预取中止(Prefetch Abort):
- 当处理器在取指令时发生错误,例如访问了非法的内存地址或者发生了内存访问冲突,就会产生预取中止异常。
- 预取中止异常处理程序可以尝试恢复错误的指令预取,例如重新从正确的地址取指令或者进行错误处理和恢复操作。如果无法恢复错误,可能会终止程序的执行并报告错误。
5. 数据中止(Data Abort):
- 当处理器在访问数据时发生错误,类似于预取中止异常,但发生在数据访问阶段。例如,访问了非法的内存地址、内存访问权限错误等情况会导致数据中止异常。
- 数据中止异常处理程序可以尝试恢复错误的数据访问,例如重新从正确的地址读取数据或者进行错误处理和恢复操作。如果无法恢复错误,可能会终止程序的执行并报告错误。
6. 外部中断请求(Interrupt Request,IRQ):
- 由外部设备通过中断控制器向处理器发送中断请求信号时产生。这是一种常见的异常类型,用于处理外部设备的事件和请求。
- 外部中断异常处理程序会根据中断源的不同进行相应的处理,例如读取外部设备的状态、处理中断请求并进行相应的操作。在处理完中断后,需要返回被中断的程序继续执行。
7. 快速中断请求(Fast Interrupt Request,FIQ):
- 快速中断请求是一种高优先级的中断,与外部中断请求类似,但具有更高的优先级和更快的响应速度。
- 快速中断请求通常用于处理时间关键的外部事件或需要快速响应的中断。在快速中断异常处理程序中,需要尽快处理中断请求并返回,以减少中断延迟。
二、异常处理过程
1. 异常进入:
- 当异常发生时,处理器会自动执行以下操作:
- 将当前程序的下一条指令地址保存到相应的连接寄存器(LR)中,以便在异常处理完成后能够返回原来的程序继续执行。
- 将当前程序状态寄存器(CPSR)的值保存到相应的保存程序状态寄存器(SPSR)中,以便在异常处理完成后能够恢复原来的处理器状态。
- 根据异常类型设置处理器模式为相应的异常模式,并禁止中断(如果需要)。
- 根据异常类型跳转到相应的异常向量地址开始执行异常处理程序。
2. 异常处理:
- 异常处理程序通常会执行以下操作:
- 保存现场:将需要保存的寄存器值保存到栈中,以便在异常处理完成后能够恢复原来的程序状态。
- 识别异常类型:根据异常向量地址或其他方式确定异常的类型,并采取相应的处理措施。
- 处理异常:根据异常类型进行具体的异常处理,例如读取外部设备状态、处理错误情况、执行特定的服务函数等。
- 恢复现场:在异常处理完成后,将保存的寄存器值从栈中恢复到相应的寄存器中,恢复处理器状态。
3. 异常返回:
- 异常处理完成后,需要返回到原来的程序继续执行。异常返回过程通常会执行以下操作:
- 将保存的程序状态寄存器(SPSR)的值恢复到当前程序状态寄存器(CPSR)中,恢复处理器的状态。
- 将连接寄存器(LR)的值减去适当的值(根据异常类型和处理器模式确定)后赋给程序计数器(PC),使处理器跳转到被中断的程序继续执行。
三、异常优先级
在 ARM 架构中,不同类型的异常具有不同的优先级。优先级从高到低依次为:复位、数据中止、快速中断请求、外部中断请求、预取中止、未定义指令、软件中断。当多个异常同时发生时,处理器会按照优先级顺序处理异常。高优先级的异常可以中断低优先级的异常处理程序。
四、异常向量表
ARM 处理器在启动时会根据硬件配置确定异常向量表的地址。异常向量表是一个存储异常处理程序入口地址的表,每个异常类型对应一个固定的地址。当异常发生时,处理器会根据异常类型跳转到相应的异常向量地址开始执行异常处理程序。
总之,ARM 异常处理机制为处理器提供了一种有效的方式来处理各种异常情况,保证了系统的稳定性和可靠性。通过合理地设计异常处理程序,可以实现对错误情况的及时处理和恢复,提高系统的容错能力。
四,指令流水线
在 ARM 架构中,指令流水线是一种提高处理器性能的技术。它将指令的执行过程分为几个阶段,每个阶段由不同的硬件单元并行执行,从而在同一时间内可以处理多条指令的不同阶段,大大提高了指令的执行效率。
一、ARM 指令流水线的阶段划分
1. 取指(Fetch):
- 从内存中读取下一条要执行的指令。处理器根据程序计数器(PC)的值从内存中获取指令,并将其放入指令流水线中。
- 在取指阶段,处理器还会进行指令预取,即提前读取后续的几条指令放入指令缓存中,以减少指令访问的延迟。
2. 译码(Decode):
- 对取到的指令进行译码,确定指令的操作码和操作数。译码阶段会解析指令的格式,识别指令的类型和操作数的来源,并将指令转换为可以被执行的控制信号。
- 在译码阶段,处理器还会进行寄存器读取,即从寄存器文件中读取指令所需的操作数。
3. 执行(Execute):
- 根据译码阶段产生的控制信号执行指令的操作。执行阶段可以进行算术运算、逻辑运算、数据传输等各种操作。
- 在执行阶段,处理器可能会访问内存或其他外部设备,以获取操作数或存储结果。
4. 访存(Memory Access):
- 如果指令需要访问内存,则在这个阶段进行内存访问操作。访存阶段可以进行数据加载(从内存中读取数据到寄存器)或数据存储(将寄存器中的数据写入内存)操作。
- 在访存阶段,处理器会根据指令的地址和操作类型访问内存,并将读取的数据或写入的数据放入数据缓存中。
5. 写回(Write Back):
- 将执行结果写回到寄存器文件中。写回阶段会将执行阶段产生的结果或访存阶段读取的数据写入到目的寄存器中,完成指令的执行。
- 在写回阶段,处理器还会更新程序计数器(PC)的值,指向下一条要执行的指令。
二、指令流水线的优势
1. 提高指令执行效率:
- 通过将指令的执行过程分为多个阶段,每个阶段由不同的硬件单元并行执行,可以在同一时间内处理多条指令的不同阶段,从而大大提高了指令的执行效率。
- 指令流水线可以减少指令执行的平均周期数(CPI),提高处理器的吞吐量。
2. 隐藏内存访问延迟:
- 指令流水线可以通过指令预取和数据缓存等技术,隐藏内存访问的延迟。当一条指令需要访问内存时,处理器可以在等待内存访问完成的同时,继续执行后续的指令,从而提高了处理器的性能。
3. 提高处理器的并行性:
- 指令流水线可以使处理器在不同的阶段同时处理不同的指令,提高了处理器的并行性。这种并行性可以通过超标量处理器和乱序执行等技术进一步提高,从而使处理器能够在同一时间内执行更多的指令。
三、指令流水线的挑战
1. 流水线冲突:
- 由于指令流水线是并行执行的,不同的指令可能会在不同的阶段同时访问相同的硬件资源,从而导致流水线冲突。流水线冲突会降低处理器的性能,甚至会导致指令执行错误。
- 常见的流水线冲突包括结构冲突(硬件资源冲突)、数据冲突(数据依赖冲突)和控制冲突(分支预测错误)等。处理器可以通过采用流水线停顿、数据前推、分支预测等技术来解决流水线冲突问题。
2. 指令相关性:
- 指令之间可能存在数据依赖、控制依赖等相关性。相关性会导致指令流水线中的某些指令无法按照预期的顺序执行,从而影响处理器的性能。
- 处理器可以通过采用数据前推、寄存器重命名、分支预测等技术来解决指令相关性问题,提高指令流水线的效率。
3. 分支预测错误:
- 当程序中存在分支指令时,处理器需要预测分支的方向和目标地址,以便继续执行后续的指令。如果分支预测错误,处理器需要清空指令流水线,并从正确的地址重新取指执行,这会导致很大的性能损失。
- 处理器可以采用各种分支预测技术,如静态分支预测、动态分支预测等,来提高分支预测的准确性,减少分支预测错误带来的性能损失。
总之,ARM 指令流水线是一种提高处理器性能的重要技术。通过将指令的执行过程分为多个阶段,每个阶段由不同的硬件单元并行执行,可以大大提高指令的执行效率。然而,指令流水线也面临着一些挑战,如流水线冲突、指令相关性和分支预测错误等。处理器可以采用各种技术来解决这些问题,提高指令流水线的效率和性能。
汇编语言
一,什么是汇编
汇编语言是一种低级编程语言,它使用助记符来代表机器指令,以便程序员更容易理解和编写程序。以下是关于汇编语言的详细介绍:
一、定义与特点
1. 与机器语言的关系:
- 汇编语言是机器语言的一种符号化表示。机器语言是由二进制代码组成的指令集,直接被计算机硬件执行。而汇编语言用易于记忆的助记符(如 MOV 表示数据传送、ADD 表示加法等)和符号来代替机器语言的二进制指令,使得程序员能够更方便地编写程序。
2. 特点:
- 直接操作硬件:汇编语言可以直接访问计算机的硬件资源,如寄存器、内存地址和 I/O 端口等。这使得汇编语言在需要对硬件进行底层控制的场景中非常有用,例如操作系统内核、设备驱动程序和嵌入式系统开发等。
- 高效性:由于汇编语言直接对应机器指令,它可以生成非常高效的代码。与高级语言相比,汇编语言程序通常占用更少的内存空间和执行时间。
- 复杂性:汇编语言的语法相对复杂,需要程序员对计算机的硬件结构和指令集有深入的了解。编写和调试汇编语言程序通常比高级语言程序更加困难和耗时。
二、汇编语言的组成
1. 指令集:
- 汇编语言的指令集是一组特定于处理器架构的指令。不同的处理器架构有不同的指令集,例如 x86、ARM、MIPS 等。每个指令通常由操作码和操作数组成,操作码指定要执行的操作,操作数指定操作的对象。
2. 寄存器和内存寻址:
- 汇编语言使用寄存器来存储数据和地址。寄存器是处理器内部的高速存储单元,可以快速访问。汇编语言还支持各种内存寻址方式,如直接寻址、间接寻址、基址加变址寻址等,以便访问内存中的数据。
3. 伪指令和宏:
- 伪指令是在汇编过程中由汇编器解释执行的指令,它们不对应实际的机器指令。伪指令用于定义数据、分配内存、控制汇编过程等。例如,DB 伪指令用于定义字节数据,DW 伪指令用于定义字数据。
- 宏是一种可以在程序中重复使用的代码片段。宏定义可以包含一组指令和参数,在程序中使用宏时,汇编器会将宏展开为实际的指令。宏可以提高程序的可读性和可维护性。
三、汇编语言的应用场景
1. 系统软件开发:
- 操作系统内核、设备驱动程序和引导程序等系统软件通常需要对硬件进行底层控制,因此常常使用汇编语言编写。汇编语言可以提供高效的代码和对硬件的直接访问,确保系统软件的性能和稳定性。
2. 嵌入式系统开发:
- 在嵌入式系统中,资源通常有限,需要高效的代码来实现特定的功能。汇编语言可以针对特定的嵌入式处理器进行优化,生成紧凑而高效的代码。此外,汇编语言还可以用于编写与硬件紧密结合的底层驱动程序和固件。
3. 性能关键的应用:
- 在一些对性能要求极高的应用领域,如游戏开发、图形处理和科学计算等,汇编语言可以提供比高级语言更高的性能。通过手动优化关键代码段,程序员可以充分发挥处理器的性能潜力。
4. 逆向工程和漏洞分析:
- 在安全领域,汇编语言常用于逆向工程和漏洞分析。通过分析二进制文件的汇编代码,可以了解程序的功能和逻辑,以及查找潜在的安全漏洞。
四、汇编语言与高级语言的比较
1. 可读性和可维护性:
- 高级语言通常具有更易于理解和维护的语法,程序员可以使用更抽象的概念和数据结构来表达程序的逻辑。而汇编语言的语法相对复杂,代码可读性较差,维护起来也更加困难。
2. 开发效率:
- 高级语言提供了丰富的库和工具,以及自动内存管理和错误处理等功能,使得开发效率更高。而汇编语言需要程序员手动管理内存和处理错误,开发过程更加繁琐和耗时。
3. 可移植性:
- 高级语言通常具有较好的可移植性,可以在不同的操作系统和硬件平台上运行。而汇编语言与特定的处理器架构紧密相关,代码的可移植性较差。
4. 性能:
- 在某些情况下,汇编语言可以生成比高级语言更高效的代码。但是,随着现代编译器的不断优化,高级语言程序的性能也在不断提高。在大多数应用场景中,高级语言的性能已经足够满足需求,而牺牲可读性和可维护性来追求极致性能的情况相对较少。
总之,汇编语言是一种低级编程语言,它使用助记符来代表机器指令,直接操作硬件资源。汇编语言具有高效性和直接访问硬件的特点,但语法复杂,可读性和可维护性较差。汇编语言在系统软件开发、嵌入式系统开发、性能关键的应用和安全领域等方面有广泛的应用。与高级语言相比,汇编语言在可读性、可维护性、开发效率和可移植性等方面存在不足,但在某些性能关键的场景中仍然具有优势。
二,汇编怎么编
三,ARM汇编指令集
ARM汇编指令集是ARM处理器所能理解和执行的指令集合,以下是其常见的指令分类及具体指令介绍:
1. 数据处理指令:
- 算术运算指令:
- ADD :加法指令,用于将两个操作数相加,并将结果存储到目标寄存器中。例如 ADD R0, R1, R2 表示将寄存器 R1 和 R2 中的值相加,结果存储到寄存器 R0 中。
- SUB :减法指令,功能与加法指令相反,用于从一个操作数中减去另一个操作数,并将结果存储到目标寄存器。如 SUB R0, R1, R2 是将 R2 的值从 R1 中减去,结果存于 R0 。
- MUL :乘法指令,实现两个操作数的乘法运算,结果根据处理器的架构可能存储在一个或多个寄存器中。
- 逻辑运算指令:
- AND :按位与指令,对两个操作数的对应位进行与运算,结果存于目标寄存器。例如 AND R0, R1, R2 ,将 R1 和 R2 按位与后的结果存入 R0 。
- ORR :按位或指令,对两个操作数的对应位进行或运算,结果存于目标寄存器。
- EOR :按位异或指令,对两个操作数的对应位进行异或运算,结果存于目标寄存器。
- BIC :按位清除指令,将一个操作数的某些位清零,具体哪些位清零由另一个操作数指定。
- 数据移动指令:
- MOV :用于将一个值(可以是立即数或寄存器中的值)移动到目标寄存器。例如 MOV R0, #10 将立即数 10 赋值给寄存器 R0 ; MOV R0, R1 则是将 R1 中的值复制到 R0 。
- MVN :按位取反指令,对操作数进行按位取反操作后将结果存储到目标寄存器。
2. 数据传输指令:
- LDR :加载字指令,用于从内存中读取数据到寄存器。例如 LDR R0, [R1] 表示将内存地址为 R1 寄存器中值所指向的地址的数据加载到寄存器 R0 中。
- STR :存储字指令,与 LDR 相反,用于将寄存器中的数据存储到内存中。如 STR R0, [R1] 是将寄存器 R0 中的值存储到内存地址为 R1 寄存器中值所指向的地址。
- LDM :加载多个字指令,可以一次从内存中加载多个数据到寄存器列表中。
- STM :存储多个字指令,一次将寄存器列表中的多个数据存储到内存中。
3. 分支指令:
- B :无条件分支指令,直接跳转到指定的地址执行程序。例如 B label 会跳转到标签 label 处继续执行程序。
- BL :分支并链接指令,在跳转到指定地址之前,会将当前指令的下一条指令的地址保存到链接寄存器(LR)中,以便后续返回。常用于函数调用。
- BX :分支并交换指令,用于在 ARM 状态和 Thumb 状态之间切换,或者在不同的处理器模式之间切换。
- 带条件分支指令,如 BEQ (相等时分支)、 BNE (不相等时分支)、 BGT (大于时分支)、 BLT (小于时分支)等,根据条件判断是否进行分支跳转。
4. 特殊指令:
- SWI :软件中断指令,用于触发软件中断,使处理器进入特定的处理程序,通常用于系统调用或异常处理。
- NOP :无操作指令,执行该指令时,处理器不进行任何实质性的操作,只是简单地将程序计数器加一,用于代码的延迟、占位或指令对齐等。
- PUSH :入栈指令,将一个或多个寄存器的值压入堆栈。
- POP :出栈指令,从堆栈中弹出数据到一个或多个寄存器中。
5. 协处理器指令:
- MCR :用于将 ARM 处理器寄存器中的数据传输到协处理器的寄存器中。
- MRC :用于将协处理器寄存器中的数据传输到 ARM 处理器的寄存器中。
此外,ARM汇编指令还涉及到各种寻址方式,如寄存器寻址、立即数寻址、寄存器移位寻址、寄存器间接寻址、基址变址寻址、多寄存器寻址等,这些寻址方式决定了指令如何获取操作数的地址。不同的 ARM 处理器架构和版本可能会对指令集有一些扩展或特定的要求,具体使用时需要参考相应的处理器手册和文档。
四,数据处理指令
五,立即数
在 ARM 汇编中,立即数是一种可以直接在指令中使用的数值。以下是关于立即数的详细介绍:
一、定义与特点
1. 立即数是一个固定的值,可以在指令中直接使用,而不需要从寄存器或内存中读取。例如,在指令 MOV R0, #10 中,#10 就是一个立即数,表示将数值 10 赋值给寄存器 R0。
2. 立即数在指令中的表示通常以“#”开头,后面跟着具体的数值。这个数值可以是整数、十六进制数或二进制数等。
3. 立即数的取值范围是有限制的。在 ARM 架构中,立即数必须能够通过一个特定的编码方式在指令中表示出来。具体来说,立即数必须能够通过一个 8 位的循环右移偶数位得到。例如,立即数 0xFF(十六进制)可以通过将 0x000000FF 循环右移 0 位得到,因此是合法的立即数;而立即数 0x123(十六进制)不能通过 8 位的循环右移偶数位得到,因此不是合法的立即数。
二、使用场景
1. 初始化寄存器:立即数常用于初始化寄存器的值。例如,在程序开始时,可以使用立即数将一些常量或初始值赋值给寄存器,以便后续的计算和操作。
2. 算术运算和逻辑运算:立即数可以作为算术运算和逻辑运算的操作数之一。例如,可以使用立即数与寄存器中的值进行加法、减法、乘法、除法、与、或、异或等运算。
3. 条件判断:立即数可以用于条件判断指令中,作为比较的基准值。例如,可以使用立即数与寄存器中的值进行比较,根据比较结果进行条件分支或设置标志位。
三、注意事项
1. 立即数的取值范围有限,因此在使用立即数时需要注意其合法性。如果使用了不合法的立即数,汇编器可能会产生错误或警告信息。
2. 立即数在指令中的编码方式可能会影响指令的长度和执行效率。在某些情况下,使用立即数可能会导致指令长度增加,从而影响程序的性能。因此,在使用立即数时需要考虑指令的长度和执行效率,选择合适的编码方式和取值范围。
3. 在不同的 ARM 处理器架构和版本中,立即数的取值范围和编码方式可能会有所不同。因此,在编写 ARM 汇编程序时,需要参考相应的处理器手册和文档,了解具体的立即数取值范围和编码方式。
总之,立即数是 ARM 汇编中一种常用的数值表示方式,可以用于初始化寄存器、进行算术运算和逻辑运算、以及条件判断等操作。在使用立即数时,需要注意其合法性、编码方式和执行效率等问题,以确保程序的正确性和性能。
六,函数的写法
在 ARM 汇编中,函数的写法通常包括以下几个部分:
一、函数定义
1. 使用标签来定义函数名,例如: function_name: 。这个标签将作为函数的入口点。
2. 在函数定义的开头,可以保存一些需要用到的寄存器,通常使用 PUSH 指令将寄存器压入堆栈。这是为了在函数执行过程中不破坏调用者的寄存器值。例如: PUSH {R4-R6,LR} 表示将寄存器 R4 到 R6 以及链接寄存器 LR 压入堆栈。
二、函数体
1. 函数体包含实现函数功能的指令序列。可以使用各种 ARM 汇编指令进行数据处理、控制流操作等。
2. 如果函数有参数,可以通过寄存器或者堆栈来传递参数。通常,前几个参数可以通过特定的寄存器传递,而更多的参数可以通过堆栈传递。
3. 如果函数有返回值,可以将返回值存储在特定的寄存器中。例如,在 ARM 中通常使用寄存器 R0 来存储函数的返回值。
三、函数返回
1. 在函数执行完毕后,需要恢复之前保存的寄存器,并返回到调用者。通常使用 POP 指令将之前压入堆栈的寄存器弹出。例如: POP {R4-R6,PC} 表示将之前保存的寄存器弹出,并将程序计数器 PC 的值恢复,从而返回到调用者。
2. 如果函数是通过 BL (分支并链接)指令调用的,还需要将链接寄存器 LR 的值赋给 PC,以实现正确的返回。可以使用 MOV PC,LR 指令来实现。
以下是一个简单的 ARM 汇编函数示例:
assembly
; 定义一个名为 add_numbers 的函数,接受两个参数并返回它们的和
add_numbers:
PUSH {R4,LR} ; 保存寄存器 R4 和链接寄存器 LR
MOV R4,R0 ; 将第一个参数复制到 R4
ADD R0,R0,R1 ; 将两个参数相加,结果存储在 R0
MOV R1,R4 ; 将第一个参数恢复到 R1,准备通过堆栈返回
POP {R4,PC} ; 恢复寄存器 R4,并返回到调用者
在这个示例中, add_numbers 函数接受两个参数,将它们相加后返回结果。函数首先保存了需要用到的寄存器,然后进行加法运算,最后恢复寄存器并返回。
需要注意的是,ARM 汇编中的函数写法可能会因不同的编译器、处理器架构和编程环境而有所不同。在实际编写汇编代码时,需要参考相应的文档和手册。
七,代码演示
preserve8 ;对齐规则
area reset, code, readonly ;设定属性
code32 ;使用32位位宽ARM
entry ;开始处
b start ;reset
nop ;undef
b deal_swi ;swi
nop ;prefetch abort
nop ;data abort
nop ;reserved
nop ;irq
nop ;fiq
deal_swi
stmfd sp!, {r4-r12, lr} ;保护现场
sub r0, lr, #4 ;获得swi的值
ldr r1, [r0] ;取出swi的地址值
bic r0, r1, #(0xff << 24) ;取出swi的值
import c_deal_swi
bl c_deal_swi ;跳转执行swi的值对应的函数
ldmfd sp!, {r4-r12, pc}^ ;带模式切换的恢复现场
start
ldr sp, =0x40001000 ;初始化svc模式的栈
mrs r0, cpsr ;取出cpsr的值
bic r0, r0, #0x1f ;清零
orr r0, r0, #0x10 ;置一
msr cpsr_c, r0 ;切换工作模式到user
ldr sp, =0x40000c00 ;初始化user模式的栈
mov r0, #1 ;r0 = 0x000001
mov r1, #1
mov r3, #0
mov r4, #100
tmp
add r3, r3,r1 ;r3 = r3 + r3
add r1,r1,r0 ;r1 = r1 + r0
cmp r1,r4 ;比较r1,r4
ble tmp ;计算1---100 值放在r3中
swi #7
mov r0, #1
mov r1, #2
mov r6, #6
import c_add ;声明要使用外部函数
bl c_add ;跳转到函数
nop ;空转
export asm_add ;声明函数可以被外部调用
asm_add
stmfd sp!, {r4-r12,lr} ;保护现场
add r0, r0,r1 ;函数执行语句
mov r6, #7 ;函数内改变变量 恢复现场后无效
ldmfd sp!, {r4-r12, pc} ;恢复现场
end ;结束
c代码
int asm_add(int x, int y);
int c_add(int a,int b)
{
int sum = asm_add(a,b);
return sum;
}
void c_deal_swi(unsigned int num)
{
switch(num)
{
case 0:
break;
case 7:
break;
default:
break;
}
}