armv8汇编绝对地址赋值_GNU风格ARM汇编语法指南(⾮常
详细)
GNU风格 ARM汇编语法指南(⾮常详细)
汇编源程序⼀般⽤于系统最基本的初始化:初始化堆栈指针、设置页表、操作ARM的协处理器等。这些初始化⼯作完成后就可以跳转到C代码main函数中执⾏。
1、GNU汇编语⾔语句格式
任何Linux汇编⾏都是如下结构:[:][}@comment
linstruction为指令
ldirective为伪操作
lpseudo-instruction为伪指令
l:为标号,GNU汇编中,任何以冒号结尾的标识符都被认为是⼀个标号,⽽不⼀定⾮要在⼀⾏的开始。
lcomment为语句的注释
下⾯定义⼀个"add"的函数,最终返回两个参数的和:
.section .text, “x”
.global add      @ give the symbol “add” external linkage
add:
ADD r0, r0, r1 @ add input arguments
MOV pc, lr  @ return from subroutine
@ end of program
注意:
lARM指令,伪指令,伪操作,寄存器名可以全部为⼤写字母,也可全部为⼩写字母,但不可⼤⼩写混⽤。
l如果语句太长,可以将⼀条语句分⼏⾏来书写,在⾏末⽤“\”表⽰换⾏(即下⼀⾏与本⾏为同⼀语句)。“\”后不能有任何字符,包含空格和制表符(Tab)。
2、GNU汇编程序中的标号symbol(或label)
标号只能由a~z,A~Z,0~9,“.”,_等(由点、字母、数字、下划线等组成,除局部标号外,不能以数字开头)字符组成。
Symbol的本质:代表它所在的地址,因此也可以当作变量或者函数来使⽤。
l段内标号的地址值在汇编时确定;
l段外标号的地址值在连接时确定。
Symbol的分类:3类(依据标号的⽣成⽅式)。
<1>基于PC的标号。基于PC的标号是位于⽬标指令前的标号或者程序中数据定义伪操作前的标号。这种标号在汇编时将被处理成PC值加上(或减去)⼀个数字常量,常⽤于表⽰跳转指令”b”等的⽬标地址,或者代码段中所嵌⼊的少量数据。
<2>基于寄存器的标号。基于寄存器的标号常⽤MAP和FIELD来定义,也可以⽤EQU来定义。这种标号在汇编时将被处理成寄存器的值加上(或减去)⼀个数字常量,常⽤于访问数据段中的数据。
gnu编译器
<3>绝对地址。绝对地址是⼀个32位数据。它可以寻址的范围为[0,232-1]即可以直接寻址整个内存空间。
特别说明:局部标号Symbol
局部标号主要在局部范围内使⽤,⽽且局部标号可以重复出现。它由两部组成:开头是⼀个0-99直接的数字,后⾯紧接⼀个通常表⽰该局部变量作⽤范围的符号。局部变量的作⽤范围通常为当前段,也可以⽤ROUT来定义局部变量的作⽤范围。
局部变量定义的语法格式:N{routname}
lN:为0~99之间的数字。
lroutname:当前局部范围的名称(为符号),通常为该变量作⽤范围的名称(⽤ROUT伪操作定义的)。
局部变量引⽤的语法格式:%{F|B}{A|T}N{routname}
l%:表⽰引⽤操作
lN:为局部变量的数字号
lroutname:为当前作⽤范围的名称(⽤ROUT伪操作定义的)
lF:指⽰编译器只向前搜索
lB:指⽰编译器只向后搜索
lA:指⽰编译器搜索宏的所有嵌套层次
lT:指⽰编译器搜索宏的当前层次
例:使⽤局部符号的例⼦,⼀段循环程序
1:
subs r0, r0, #1 @每次循环使r0=r0-1
bne 1F      @跳转到1标号去执⾏
注意:
l如果F和B都没有指定,编译器先向前搜索,再向后搜索
l如果A和T都没有指定,编译器搜索所有从当前层次到宏的最⾼层次,⽐当前层次低的层次不再搜索。
l如果指定了routname,编译器向前搜索最近的ROUT伪操作,若routname与该ROUT伪操作定义的名称不匹配,编译器报告错误,汇编失败。
3、GNU汇编程序中的分段
<1>.section伪操作
.section {,””}
Starts a new code or data section. Sections in GNU are called .text, a code section, .data, an initialized data section, and .bss, an uninitialized data section.
These sections have default flags, and the linker understands the default names(similar directive to the armasm directive AREA).The following are allowable.section flagsfor ELF format files:
Meaning
a      allowable section
w      writable section
x      executable section
中⽂解释:
⽤户可以通过.section伪操作来⾃定义⼀个段,格式如下:
.section section_name [, "flags"[, %type[,flag_specific_arguments]]]
每⼀个段以段名为开始,以下⼀个段名或者⽂件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与arm asm中的AREA相同)。下⾯是ELF格式允许的段标志flags:
含义
a允许段
w可写段
x执⾏段
例:定义⼀个“段”
.section .mysection    @⾃定义数据段,段名为“.mysection”
.align  2
strtemp:
.ascii  "Temp string \n\0" @对这⼀句的理解,我觉得应该是:将"Temp string \n\0"这个字符串存储在以标号strtemp:
@为起始地址的⼀段内存空间⾥
<2>汇编系统预定义的段名
<    @代码段
l.data    @初始化数据段.data Read-write initialized long data.
l.bss    @未初始化数据段
l.sdata  @.sdata Read-write initialized short data.
l.sbss    @
注意:源程序中.bss段应该在.text段之前。
4、GNU汇编语⾔定义⼊⼝点
汇编程序的缺省⼊⼝是_start标号,⽤户也可以在连接脚本⽂件中⽤ENTRY标志指明其它⼊⼝点。
例:定义⼊⼝点
.section .data
< initialized data here>
.section .bss
< uninitialized data here>
.section .text
.globl  _start
_start:
5、GNU汇编程序中的宏定义
格式如下:
.macro宏名参数名列表@伪指令.macro定义⼀个宏
宏体
.endm                  @.endm表⽰宏结束
如果宏使⽤参数,那么在宏体中使⽤该参数时添加前缀“\”。宏定义时的参数还可以使⽤默认值。可以使⽤.exitm伪指令来退出宏。
例:宏定义
.macro SHIFTLEFT a, b
.if \b < 0
MOV \a, \a, ASR #-\b
.exitm
.endif
MOV \a, \a, LSL #\b
.endm
6、GNU汇编程序中的常数
<1>⼗进制数以⾮0数字开头,如:123和9876;
<2>⼆进制数以0b开头,其中字母也可以为⼤写;
<3>⼋进制数以0开始,如:0456,0123;
<4>⼗六进制数以0x开头,如:0xabcd,0X123f;
<5>字符串常量需要⽤引号括起来,中间也可以使⽤转义字符,如: “You are welcome!\n”;
<6>当前地址以“.”表⽰,在GNU汇编程序中可以使⽤这个符号代表当前指令的地址;
<7>表达式:在汇编程序中的表达式可以使⽤常数或者数值, “-”表⽰取负数, “~”表⽰取补,“<>”表⽰不相等,其他的符号如:+、-、*、/、%、、>>、|、&、^、!、==、>=、<=、&&、||跟C语⾔中的⽤法相似。
7、GNU ARM汇编的常⽤伪操作
在前⾯已经提到过了⼀些为操作,还有下⾯⼀些为操作:
l数据定义伪操作:.byte,.short,.long,.quad,.float,.string/.asciz/.ascii,重复定义伪操作.rept,赋值语句.equ/.set;
l函数的定义;
l对齐⽅式伪操作.align;
l源⽂件结束伪操作.end;
l.include伪操作;
lif伪操作;
l.global/ .globl伪操作;
l列表控制语句;
别于GNUAS汇编的通⽤伪操作,下⾯是ARM特有的伪操作:
.reg,.unreq,.code,.thumb,.thumb_func,.thumb_set,.ltorg,.pool
<1>数据定义伪操作
l.byte:单字节定义,如:.byte 1,2,0b01,0x34,072,'s';
l.short:定义双字节数据,如:.short 0x1234,60000;
l.long:定义4字节数据,如:.long 0x12345678,23876565
l.quad:定义8字节,如:.quad 0x1234567890abcd
l.float:定义浮点数,如:.float0f-314159265358979323846264338327\
95028841971.693993751E-40 @- pi
l.string/.asciz/.ascii:定义多个字符串,如:
.string "abcd", "efgh", "hello!"
.
asciz "qwer", "sun", "world!"
.ascii "welcome\0"
注意:ascii伪操作定义的字符串需要⾃⾏添加结尾字符'\0'。
.rept重复次数
数据定义
.endr @结束重复定义
例:
.rept 3
.byte 0x23
.endr
l.equ/.set:赋值语句,格式如下:
.equ(.set)变量名,表达式
例:
.equ abc, 3 @让abc=3
<2>函数的定义伪操作
l函数的定义,格式如下:
函数名:
函数体
返回语句
⼀般的,函数如果需要在其他⽂件中调⽤,需要⽤到.global伪操作将函数声明为全局函数。为了不⾄于在其他程序在调⽤某个C函数时发⽣混乱,对寄存器的使⽤我们需要遵循APCS准则。函数编译器将处理函数代码为⼀段.global的汇编码。
l函数的编写应当遵循如下规则:
a.a1-a4寄存器(参数、结果或暂存寄存器,r0到r3的同义字)以及浮点寄存器f0-f3(如果存在浮点协处理器)在函数中是不必保存的;
b.如果函数返回⼀个不⼤于⼀个字⼤⼩的值,则在函数结束时应该把这个值送到r0中;
c.如果函数返回⼀个浮点数,则在函数结束时把它放⼊浮点寄存器f0中;
d.如果函数的过程改动了sp(堆栈指针,r13)、fp(框架指针,r11)、sl(堆栈限制,r10)、lr(连接寄存器,r14)、v1-v8(变量寄存器,r4到r11)和f4-f7,那么函数结束时这些寄存器应当被恢复为包含在进⼊函数时它所持有的值。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。