自学内容网 自学内容网

汇编(实现C语言程序的调用)

一、ARM汇编指令

  1. mov: 将一个值或寄存器的内容移动到另一个寄存器中。这个指令可以用来赋值。

    示例:mov r0, #5 // 将立即数 5 移动到寄存器 r0

  2. add: 执行加法操作,将两个操作数相加,并将结果存储在目标寄存器中。

    示例:add r0, r1, r2 // 将 r1 和 r2 的值相加,并将结果存储在 r0 中

  3. sub: 执行减法操作,从一个寄存器的值中减去另一个寄存器的值,并将结果存储在目标寄存器中。

    示例:sub r0, r1, r2 // 计算 r1 - r2 的值,并将结果存储在 r0 中

  4. ldr: 从内存中加载数据到寄存器中。

    示例:ldr r0, [r1] // 从 r1 指向的地址加载数据到 r0 中

  5. bic: 对两个操作数执行按位清除运算,保留第一个操作数中的位,而将第二个操作数中的位清零。

    示例:bic r0, r1, r2 // 清除 r1 中与 r2 中相同的位,将结果存储在 r0 中

  6. orr: 对两个操作数执行按位或运算。

    示例:orr r0, r1, r2 // 将 r1 和 r2 的位进行按位或运算,结果存储在 r0 中

  7. cmp: 比较两个寄存器中的值,设置相应的标志位(如零标志、负标志等),但不存储结果。

    示例:cmp r0, r1 // 比较 r0 和 r1 的值

  8. stmfd: 将多个寄存器的内容存入内存,按全降序存储,通常用于保存寄存器状态。

    示例:stmfd sp!, {r0, r1, r2} // 将 r0, r1, r2 存储到栈中

  9. ldmfd: 从内存中加载多个寄存器的内容,按全升序恢复寄存器状态。

    示例:ldmfd sp!, {r0, r1, r2} // 从栈中加载 r0, r1, r2 的值

二、跳转语句

  1. b: 无条件跳转指令,跳转到指定的标签或地址。这是ARM汇编中最常用的跳转指令。

    示例:b label // 跳转到名为 label 的位置

  2. bl: 带链接的跳转,除了跳转到指定地址外,还将返回地址(下一条指令的地址)保存到链接寄存器(LR 或 r14)中。常用于子程序调用。

    示例:bl function // 跳转到 function,并将返回地址存储在 LR 中

  3. bx: 通过指定的寄存器地址跳转,并且可以根据寄存器的最低位设置处理器的状态(如进入 ARM 或 Thumb 状态)。它通常用于从子程序返回。

    示例:bx r0 // 跳转到 r0 寄存器中存储的地址

栈指针寄存器

  • SP(栈指针寄存器): SP 寄存器用于指向当前栈的顶部。栈通常用于存储局部变量、保存返回地址等。当使用 stmfd 和 ldmfd 指令时,stack pointer (SP) 寄存器可用于管理函数调用和返回。

CPSR 寄存器相关指令

  1. mrs: 从 CPSR(当前程序状态寄存器)读取数据。当需要获取当前状态或标志位时,使用此指令。

    示例:mrs r0, cpsr // 将 CPSR 的值加载到 r0 中

  2. msr: 设置 CPSR 的某些位。这可以用于改变处理器的状态或控制特权级别。

    示例:msr cpsr_c, r0 // 将 r0 的内容写入 CPSR 中的控制位

三、汇编

preserve8               ; 保留8字节对齐  
area reset, code, readonly ; 定义一个名为“reset”的只读代码区域  
code32                  ; 设定代码为32位  
entry                   ; 定义入口点  

b start                 ; 跳转到 start 标签,开始程序执行  
ldr pc, =do_undifined   ; 将 do_undifined 的地址加载到程序计数器(PC),设置未定义指令处理  
ldr pc, =do_swi        ; 将 do_swi 的地址加载到 PC,设置软件中断处理  
ldr pc, =do_p_abort    ; 将 do_p_abort 的地址加载到 PC,设置预取中止处理  
ldr pc, =do_d_abort    ; 将 do_d_abort 的地址加载到 PC,设置数据中止处理  
nop                     ; 空操作,通常用于填充或延迟  
ldr pc, =do_irq        ; 将 do_irq 的地址加载到 PC,设置外部中断处理  
ldr pc, =do_fiq        ; 将 do_fiq 的地址加载到 PC,设置快速中断处理  

do_fiq                  ; 快速中断处理程序  
b do_fiq              ; 无限循环,等待快速中断  

do_irq                  ; 外部中断处理程序  
import irq_handler    ; 导入 irq_handler 函数  
sub lr, lr, #4        ; 将链接寄存器(LR)减去4,以调整返回地址  
stmfd sp!, {r0-r12, lr} ; 将 r0-r12 和 LR 保存到栈中,进行现场保护  
bl irq_handler        ; 调用中断处理程序  
ldmfd sp!, {r0-r12, pc}^ ; 恢复寄存器并返回  

do_d_abort              ; 数据中止处理程序  
b do_d_abort          ; 无限循环,等待数据中止  

do_p_abort              ; 预取中止处理程序  
b do_p_abort          ; 无限循环,等待预取中止  

do_swi                  ; 软件中断处理程序  
import swi_handler     ; 导入 swi_handler 函数  
stmfd sp!, {r0-r12, lr} ; 保存 r0-r12 和 LR 到栈中  
bl swi_handler        ;  调用软件中断处理程序  
ldmfd sp!, {r0-r12, pc}^ ; 恢复寄存器的工作模式并返回

do_undifined            ; 未定义指令处理程序  
b do_undifined        ; 无限循环,等待未定义指令  

start                   ; 程序启动点  
ldr sp, =0x40001000  ; 将栈指针(SP)初始化为指定地址  

mrs r0, cpsr          ; 读取当前程序状态寄存器(CPSR)  
bic r0, r0, #0x1F     ; 清除 CPSR 中的模式位  
orr r0, r0, #0x12    ; 设置 CPSR 进入 irq 模式  
bic r0, #(1 << 7)     ; 清除 CPSR 中的 F 标志位  
msr cpsr_c, r0       ; 更新 CPSR  

ldr r0, =0x40001000  ; 将地址 0x40001000 加载到 r0   
sub r0, r0, #1024    ; 计算栈顶地址  
mov sp, r0           ; 设置栈指针 SP  

mrs r0, cpsr          ; 读取当前 CPSR  
bic r0, r0, #0x1F     ; 清除模式位  
orr r0, r0, #0x10    ; 设置 CPSR 进入 user 模式  
msr cpsr_c, r0       ; 更新 CPSR  

ldr r0, =0x40001000  ; 将地址 0x40001000 加载到 r0  
sub r0, r0, #2048    ; 计算新的栈顶地址  
mov sp, r0           ; 设置栈指针 SP  

import main           ; 导入 main 函数  
b main               ; 跳转到 main 函数  

asm_fn                  ; 汇编函数的标签  
export asm_fn         ; 导出 asm_fn 函数  
swi #7                ; 触发软件中断,调用系统服务  
bx lr                 ; 返回到调用者  

finished                ; 完成标签  
b finished            ; 无限循环,等待程序结束  

end                    ; 汇编代码的结束标志


原文地址:https://blog.csdn.net/m0_71459026/article/details/142354338

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!