ARM64的汇编器
(1)ARM公司官方的汇编器; (2)GNU AS汇编器:aarch64-linux-gnu-as; (3)gcc采用as作为汇编器,所以汇编码是AT&T格式; (4)AT&T格式:源于贝尔实验室; (5)ARM格式:ARM官方汇编语法;
汇编语法
(1)label:任何以冒号结尾的标识符,都被认为是一个标号; (2)注释: “//”,注释 “#”,在一行的开始,注释整行; (3)指令、伪指令、寄存器,可以全部大写或者小写,GNU默认风格是小写; (4)Symbol:代表它所在的地址,也可以当作变量或者函数来使用; 全局symbol, 可以用.global声明; 局部symbol, 局部范围使用,开头以0-99为标号,通常和b指令结合使用
f:告诉编译器向前搜索; b:告诉编译器向后搜索;
伪指令
(1).glign对齐,填充数据实现对齐。ARM64系统中,第一个参数表示2^n大小; (2)数据定义伪指令
伪指令 | 描述 |
---|
.byte | 把8位数当作数据插入汇编中 | .hword | 把16位数当作数据插入汇编中 | .long和.int | 把32位数当作数据插入汇编中 | .quad | 把64位数当作数据插入汇编中 | .float | 把浮点数当作数据插入汇编中 | .ascii “string” | 把string当作数据插入汇编中,末尾需手动添加’\0’ | .asciz “string” | 类似.ascii,在string后自动插入一个’\0’ | .rept | 重复定义 | .equ | 赋值操作 | .set | 赋值操作 |
函数相关伪操作
伪指令 | 描述 |
---|
.global | 定义一个全局的符号 | .include | 引用头文件 | .if, .else, .endif | 控制语句 | if语句 | | .ifdef symbol .ifndef symbol .ifc string1,string2 .ifeq expression .ifeqs string1,string2 .ifge expression .ifle expression .ifle expression<.ifne expression> | 判断symbol是否有定义 判断symbol是否没定义 判断字符串是否相等 判断exp是否为0 等同于.ifc exp是否大于等于0 exp是否小于等于0 exp是否不等于0 |
与段相关的伪指令
(1).section:表示接下来的汇编会链接到哪个段里,如代码段、数据段等
每一个段都以段名开始,以下一个段名或文件结尾结束
.section name, "flags"
“flags”,表示段的属性,可写,可执行等;
.section ".idmap.txt","awx"
//表示下面代码是在".idmap.txt"段里,具有可分配,可写和可执行的属性;
(2).pushsection:把下面代码push到指定section中; .popsection:技术push,成对使用;
仅仅是把pushsection/.popsection之间的代码,加载到指定section中,其他不变; 实例1:使用伪指令,实现一个类似linux内核中表的定义;
/*
* as lab1:pesudo code, realize a table
*/
.align 3
.global func_addr
func_addr:
.quad 0x800800
.quad 0x800860
.quad 0x800880
.align 3
.global func_string
func_string:
.asciz "func_a"
.asciz "func_b"
.asciz "func_c"
.align 3
.global func_num_syms
func_num_syms:
.quad 3
extern unsigned long func_addr[];
extern unsigned long func_num_syms;
extern char func_string[];
static int print_func_name(unsigned long addr)
{
int i;
char *p, *string;
for (i = 0; i < func_num_syms; i++) {
if (addr == func_addr[i])
goto found;
}
return 0;
found:
p = &func_string;
while (1) {
p++;
if (*p == '\0')
i--;
if (i == 0) {
p++;
string = p;
uart_send_string(string);
break;
}
}
return 0;
}
宏
(1).macro和.endm组成一个宏; (2).macro后面跟着的依次是宏名称,宏参数; (3)在宏中使用参数,需要添加前缀"";
.macro add a,b //宏名称add,参数a,b
(4)红参数定义时,可以设置初始值
.macro test p1=0 p2//可以用test a,b或者test b来使用
(5)宏可以使用空格
.macro label 1
\1 :
.endm
(6)使用"()"表示字符串结束
.macro kernel_ventry, el, label
b el\()\el\()_\label
//在arm/arm64/kernel/entry.S文件,表示el1_irq
练习2:
/*
* lab02:macro test
*/
.align 3
.macro add_func add,a,b
mov x0, \a
mov x1, \b
bl add_\()\add
.endm
.align 3
.global add_1
add_1:
add x0,x0,x1
add x0,x0,1
ret
.global add_2
add_2:
add x0,x0,x1
ret
.global macro_test1
macro_test1:
mov x9,x30
add_func 1,x0,x1
mov x30, x9
ret
.global macro_test2
macro_test2:
mov x9,x30
add_func 2,x0,x1
mov x30, x9
ret
print_func_name(0x800880);
unsigned long val1 = 0,val2=0;
val1 = macro_test1(3,5);
val2 = macro_test2(3,5);
ARM64编译选项
-EB:用于大端模式的CPU, -EL表示小端模式; -mabi:指定ABI模式,ilp32表示elf32, lp6表示ELF64,默认lp64; -mcpu=processor+extension: 指定CPU型号,比如cortex-a72; -march=,用于指定架构,比如armv-8.2-a;
yu@sys:~$ aarch64-linux-gnu-as --help
AArch64-specific assembler options:
-mbig-endian assemble for big-endian
-mlittle-endian assemble for little-endian
-mverbose-error output verbose error messages
-mno-verbose-error do not output verbose error messages
-mabi=<abi name> specify for ABI <abi name>
-mcpu=<cpu name> assemble for CPU <cpu name>
-march=<arch name> assemble for architecture <arch name>
-EB assemble code for a big-endian cpu
-EL assemble code for a little-endian cpu
特殊字符
“//”注释 “#”: 在一行开头,注释一行;还可以表示立即数; “#:lo12”:表示地12位;
adrp x0,foo
ldx x0,[x0,
“ldr”:伪操作;
ARM64特有的伪操作;
.bss:切换到bss段; .dword/.xword:64位数据; name .reg register_name:为寄存器创建别名;
foo .req x0
code
|