如何在特权模式下用arm汇编

如何在特权模式下用arm汇编,第1张

1、首先通过Keil5,在stm32H743非中断模式下,使用主堆栈指针下的汇编语句查看。

2、然后理解这个汇编逻辑后,将有利于更自由的进行程序调试,查找BUG。

3、最后即可在特权模式下用arm汇编。

#include< reg51h>

#include< stdioh>

#include< stringh>

#define INBUF_LEN 4 //数据长度

unsigned char inbuf1[INBUF_LEN];

unsigned char checksum,count3 , flag,temp,ch;

bit read_flag=0;

sbit cp=P1^1;

sbit DIR=P1^2;

int i;

unsigned int xdata RAMDATA; /定义RAM地址指针/

unsigned char a[6] ={0x11,0x22,0x33,0x44,0x55,0x66} ;

void init_serialcomm(void)

{

SCON=0x50; //在110592MHz下,设置串行口波特率为9600,方式1,并允许接收

PCON=0x00;

ES=1;

TMOD=0x21; //定时器工作于方式2,自动装载方式

TH0=(65536-1000)%256;

TL0=(65536-1000)/256;

TL1=0xfd;

TH1=0xfd;

ET0=1;

TR0=1;

TR1=1;

// TI=0;

EA=1;

// TI=1;

RAMDATA=0x1F45;

}

void serial () interrupt 4 using 3

{

if(RI)

{ RI=0;

ch=SBUF;

TI=1; //置SBUF空

switch(ch)

{

case 0x01 :printf("A"); TI=0;break;

case 0x02 :printf("B"); TI=0;break;

case 0x03 :printf("C"); TI=0;break;

case 0x04 :printf("D"); TI=0;break;

default :printf("fg"); TI=0;break;

}

}

}

//向串口发送一个字符

void timer0() interrupt 1 using 3{

// char i;

flag++;

TH0=0x00;

TL0=0x00;

if(flag==10)

{// cp=!cp;

// for(i=0;i<6;i++)

P2=0x25;

TI=1;

temp=RAMDATA;

printf("%c",temp);

TI=0;

// RAMDATA--;

flag=0;

}

}

//主程序

main()

{

init_serialcomm(); //初始化串口

//向6264中送数据

{

RAMDATA=0x33;

}

while(1)

{

RAMDATA=0x33;;

}

}

汇编主要是要了解CPU指令及用法,常说的是PC机的x86汇编,指令是x86的复杂指令集。

arm汇编是arm的精简指令集,比x86容易学,程序格式倒是和x86汇编差不多。

C语言ARM的和x86的差不多,除了对硬件寄存器 *** 作不同,其它语法和流程都一样。

arm汇编程序每一行是指定arm core执行一条指令,每条指令都是硬件相关。

如:LDR R3, #1 ;用LDR指令将数值1放入R3寄存器准备参与运算

C语言与arm指令无关,只与逻辑运算有关,指定硬件地址的 *** 作才与硬件相关;

如果用arm编译器来编译,每行可能编译出1到多条arm指令。

如:i++; //变量 i 递增1等效于LDR R3,#1 ;

用LDR指令将数值1放入R3寄存器准备参与运算ADD R2, R2, R3 ;

用ADD指令将R2、R3寄存器里的数值相加后放回R2寄存器以上等效汇编的R2、R3寄存器只是为了举例,C语言不像汇编,不需要由程序员指定用哪个寄存器参与运算,编译器编译时会根据程序结构自动判断选择。

无论是c语言还是汇编语言,编译器编译后的结果是机器执行码,很多人因为汇编语言比较难懂及指令相关,所以以为它就是机器语言,其实它仍是人类设计的编写程序的语言,仍需要编译器编译成机器码才能执行,它只是比C语言更接近硬件而已。

ADD proc

arg_C equ 0xC

arg_8 equ 8

arg_4 equ 4

arg_0 equ 0

MOV R12, SP

STMFD SP!, {R0-R3} ;四个参数

STMFD SP!, {R4-R10,R12,LR}

SUB SP, SP, #0x10

LDR R0, [SP,#0x34+arg_0]

LDR R1, [SP,#0x34+arg_4]

LDR R2, [SP,#0x34+arg_8]

ADD R0, R0, R1

ADD R0, R0, R2

ADD SP, SP, #0x10

LDMFD SP, {R4-R10,SP,PC}

ENDP

如果参数传递大于 4 个,那么你在 BL 的地方应使用:

STR R0, [SP,#0x8] ;第七个

STR R0, [SP,#0x4] ;第六个

STR R0, [SP,#0x0] ;第五个

============================================

我理解你的意思了

LDR r0,=0x1

LDR r1,=0x2

LDR r2,=0x3

BL add

改为:

LDR r0,=0x1

STR R0, [SP,#0x0]

LDR r1,=0x2

STR R1, [SP,#0x4]

LDR r2,=0x3

STR R2, [SP,#0x8]

BL ADD

你是这个意思吧

------------

int a = R0

int b = R1

int c = R2

在linux源代码中会有一部分c语言与汇编语言相交融的部分。

其中linux中汇编语言采用的不是我们通用的intel的汇编语言,而是采用的是AT&T格式的汇

编语言,它们之间有一些差别:

1

目标与源的方向不大一样

mov

ax,

bx

mov

%bx,

%ax

2

AT&T寄存器前要加入%

ax

%ax

3

AT&T立即数前面要加上$

add

ax,

4

add

%ax,$4

4

对于访问指令的 *** 作数大小

intel的格式是在 *** 作数前加上BYTE

PTR、DWORD

PTR等等

AT&T格式:在 *** 作数后面加上b、l、w等

MOV

AL,

BYTE

PTR

FOO(intel)

movb

FOO,

%al

(AT&T)

5

间接寻址:

SECTION:[BASE+INDEXSCALE+DISP]

Section:disp(base,

index,

scale)

C语言中插入汇编代码比纯粹的汇编要难,因为要设计到“如何分配使用寄存器、怎样与C语

言中变量相结合”

下面“=”代表只读,“+”代表读写

每个输出部分均以=开始

比如我想定义一个char型的变量,放入ax中

register

char

_temp

asm

("ax");

register

char

_temp

__asm__

("ax");

以上两种方式均正确

在这里我们通常看到普通的寄存器前面有两个%,代表下面的意思:第一寄存器前要有一个%

第二对于一个模板前要加入一个%

下面以一个在内核中常见的目的为了实现原子 *** 作的一个函数为例子atomic_add来介绍

static

__inline__

void

atomic_add(int

i,

atomic_t

v)

{

__asm__

__volatile__(

LOCK

"addl

%1,

%0"

:"=m"(v->counter)

:"ir"(i),

"m"(v->counter)

);

}

ir代表一个寄存器中的直接 *** 作数

首先一个头部:__asm__

__volatile__();

asm();

__asm__();告诉编译器里面是汇编语言

:第一个冒号是输出部分:第二个冒号是输入部分

其实还有第三个冒号:代表着损坏部分

asm("汇编语句"

:输出部分

:输入部分

:损坏部分)

%0、%1

等等代表着一种模板 *** 作数,其中数字到几取决于cpu寄存器数量

"m",

"v",

"o"

--内存单元

"r"

任意寄存器

"q"

表示eax、ebx、ecx、edx之一

"i",

"h"

表示立即数

"a",

"b",

"c",

"d"表示eax、ebx、ecx、edx

关键字LOCK表示在执行的时候把系统总线锁住,不让其他

cpu干扰。

dseg segment

tab db '0123456789ABCDEF'

str db 4 dup(),'$'

dseg ends

cseg segment

assume cs:cseg,ds:dseg

begin: mov ax,dseg

mov ds,ax

mov ax,1

mov bx,2

mov cx,99

next: add ax,bx

inc bx

loop next

call disp

mov ah,4ch

int 21h

disp proc

lea si,str

mov cl,4

mov di,4

abc: rol ax,cl

mov dx,ax

and ax,0fh

lea bx,tab

xlat

mov [si],al

inc si

mov ax,dx

dec di

jnz abc

lea dx,str

mov ah,9

int 21h

ret

disp endp

cseg ends

end begin

stack 100h

data

code

start:

mov ax, @data

mov ds, ax

mov cx, 50 ;循环50次

xor ax, ax

label:

mov bx, cx

shl bx, 1 ;相当于将当前循环计数乘2,用来做加法

add ax, bx

loop label ;循环完成后,结果放在AX中

mov ax, 4c00h

int 21h

在ARM汇编语言程序里,有一些特殊指令助记符,这些助记符与指令系统的助记符不同,没有相对应的 *** 作码,通常称这些特殊指令助记符为伪指令,他们所完成的 *** 作称为伪 *** 作。伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,这些伪指令仅在汇编过程中起作用,一旦汇编结束,伪指令的使命就完成。

在ARM的汇编程序中,有如下几种伪指令:符号定义伪指令、数据定义伪指令、汇编控制伪指令、宏指令以及其他伪指令。

411 符号定义(Symbol Definition)伪指令

符号定义伪指令用于定义ARM汇编程序中的变量、对变量赋值以及定义寄存器的别名等 *** 作。常见的符号定义伪指令有如下几种:

— 用于定义全局变量的GBLA、GBLL和GBLS。

— 用于定义局部变量的LCLA、LCLL和LCLS。

— 用于对变量赋值的SETA、SETL、SETS。

— 为通用寄存器列表定义名称的RLIST。

1、 GBLA、GBLL和GBLS

语法格式:

GBLA(GBLL或GBLS) 全局变量名

GBLA、GBLL和GBLS伪指令用于定义一个ARM程序中的全局变量,并将其初始化。其中:

GBLA伪指令用于定义一个全局的数字变量,并初始化为0;

GBLL伪指令用于定义一个全局的逻辑变量,并初始化为F(假);

GBLS伪指令用于定义一个全局的字符串变量,并初始化为空;

由于以上三条伪指令用于定义全局变量,因此在整个程序范围内变量名必须唯一。

使用示例:

GBLA Test1 ;定义一个全局的数字变量,变量名为Test1

Test1 SETA 0xaa ;将该变量赋值为0xaa

GBLL Test2 ;定义一个全局的逻辑变量,变量名为Test2

Test2 SETL {TRUE} ;将该变量赋值为真

GBLS Test3 ;定义一个全局的字符串变量,变量名为Test3

Test3 SETS “Testing” ;将该变量赋值为“Testing”

2、 LCLA、LCLL和LCLS

语法格式:

LCLA(LCLL或LCLS) 局部变量名

LCLA、LCLL和LCLS伪指令用于定义一个ARM程序中的局部变量,并将其初始化。其中:

LCLA伪指令用于定义一个局部的数字变量,并初始化为0;

LCLL伪指令用于定义一个局部的逻辑变量,并初始化为F(假);

LCLS伪指令用于定义一个局部的字符串变量,并初始化为空;

以上三条伪指令用于声明局部变量,在其作用范围内变量名必须唯一。

使用示例:

LCLA Test4 ;声明一个局部的数字变量,变量名为Test4

Test3 SETA 0xaa ;将该变量赋值为0xaa

LCLL Test5 ;声明一个局部的逻辑变量,变量名为Test5

Test4 SETL {TRUE} ;将该变量赋值为真

LCLS Test6 ;定义一个局部的字符串变量,变量名为Test6

Test6 SETS “Testing” ;将该变量赋值为“Testing”

3、 SETA、SETL和SETS

语法格式:

变量名 SETA(SETL或SETS) 表达式

伪指令SETA、SETL、SETS用于给一个已经定义的全局变量或局部变量赋值。

SETA伪指令用于给一个数学变量赋值;

SETL伪指令用于给一个逻辑变量赋值;

SETS伪指令用于给一个字符串变量赋值;

其中,变量名为已经定义过的全局变量或局部变量,表达式为将要赋给变量的值。

使用示例:

LCLA Test3 ;声明一个局部的数字变量,变量名为Test3

Test3 SETA 0xaa ;将该变量赋值为0xaa

LCLL Test4 ;声明一个局部的逻辑变量,变量名为Test4

Test4 SETL {TRUE} ;将该变量赋值为真

4、 RLIST

语法格式:

名称 RLIST {寄存器列表}

RLIST伪指令可用于对一个通用寄存器列表定义名称,使用该伪指令定义的名称可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器访问次序为根据寄存器的编号由低到高,而与列表中的寄存器排列次序无关。

使用示例:

RegList R >

以上就是关于如何在特权模式下用arm汇编全部的内容,包括:如何在特权模式下用arm汇编、求一汇编小程序!用ARM汇编语言完成一个C语言嵌入式汇编方式实现字符串(数组)拷贝的功能、arm编程与C语言的编程区别和方法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10142775.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存